blob: 4351fa7b28162b73def40e5e8b8e78a1c44b8beb [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d19842009-02-19 16:33:1227
wnwenbdc444e2016-05-25 13:44:1528
jochen9ea8fdbc2014-09-25 13:21:3529# The NetscapePlugIn library is excluded from pan-project as it will soon
30# be deleted together with the rest of the NPAPI and it's not worthwhile to
31# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3832_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3233 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3834)
35
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Fragment of a regular expression that matches C++ and Objective-C++
38# implementation files.
39_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
40
wnwenbdc444e2016-05-25 13:44:1541
[email protected]06e6d0ff2012-12-11 01:36:4442# Regular expression that matches code only used for test binaries
43# (best effort).
44_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4945 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3247 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1248 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4449 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4950 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0551 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4952 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4453 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4954 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4956 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4958 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d19842009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
[email protected]127f18ec2012-06-16 05:05:5975_BANNED_OBJC_FUNCTIONS = (
76 (
77 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2078 (
79 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5980 'prohibited. Please use CrTrackingArea instead.',
81 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
82 ),
83 False,
84 ),
85 (
[email protected]eaae1972014-04-16 04:17:2686 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2087 (
88 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5989 'instead.',
90 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
91 ),
92 False,
93 ),
94 (
95 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2096 (
97 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5998 'Please use |convertPoint:(point) fromView:nil| instead.',
99 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
100 ),
101 True,
102 ),
103 (
104 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20105 (
106 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59107 'Please use |convertPoint:(point) toView:nil| instead.',
108 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
109 ),
110 True,
111 ),
112 (
113 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20114 (
115 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59116 'Please use |convertRect:(point) fromView:nil| instead.',
117 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
118 ),
119 True,
120 ),
121 (
122 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20123 (
124 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59125 'Please use |convertRect:(point) toView:nil| instead.',
126 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
127 ),
128 True,
129 ),
130 (
131 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20132 (
133 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59134 'Please use |convertSize:(point) fromView:nil| instead.',
135 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
136 ),
137 True,
138 ),
139 (
140 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20141 (
142 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59143 'Please use |convertSize:(point) toView:nil| instead.',
144 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
145 ),
146 True,
147 ),
148)
149
150
151_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20152 # Make sure that gtest's FRIEND_TEST() macro is not used; the
153 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30154 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'FRIEND_TEST(',
157 (
[email protected]e3c945502012-06-26 20:01:49158 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20159 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
160 ),
161 False,
[email protected]7345da02012-11-27 14:31:49162 (),
[email protected]23e6cbc2012-06-16 18:51:20163 ),
164 (
165 'ScopedAllowIO',
166 (
[email protected]e3c945502012-06-26 20:01:49167 'New code should not use ScopedAllowIO. Post a task to the blocking',
168 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20169 ),
[email protected]e3c945502012-06-26 20:01:49170 True,
[email protected]7345da02012-11-27 14:31:49171 (
nyad2c548b2015-12-09 03:22:32172 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10173 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49174 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22175 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31176 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51177 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
178 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09179 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49180 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
181 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41182 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
183 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48184 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
185 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01186 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54187 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13188 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
189 "gnubby_auth_handler_linux\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53190 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
191 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45192 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
193 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
194 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
195 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
196 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49197 ),
[email protected]23e6cbc2012-06-16 18:51:20198 ),
[email protected]52657f62013-05-20 05:30:31199 (
tomhudsone2c14d552016-05-26 17:07:46200 'setMatrixClip',
201 (
202 'Overriding setMatrixClip() is prohibited; ',
203 'the base function is deprecated. ',
204 ),
205 True,
206 (),
207 ),
208 (
[email protected]52657f62013-05-20 05:30:31209 'SkRefPtr',
210 (
211 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22212 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31213 ),
214 True,
215 (),
216 ),
217 (
218 'SkAutoRef',
219 (
220 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22221 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31222 ),
223 True,
224 (),
225 ),
226 (
227 'SkAutoTUnref',
228 (
229 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22230 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31231 ),
232 True,
233 (),
234 ),
235 (
236 'SkAutoUnref',
237 (
238 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
239 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22240 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31241 ),
242 True,
243 (),
244 ),
[email protected]d89eec82013-12-03 14:10:59245 (
246 r'/HANDLE_EINTR\(.*close',
247 (
248 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
249 'descriptor will be closed, and it is incorrect to retry the close.',
250 'Either call close directly and ignore its return value, or wrap close',
251 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
252 ),
253 True,
254 (),
255 ),
256 (
257 r'/IGNORE_EINTR\((?!.*close)',
258 (
259 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
260 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
261 ),
262 True,
263 (
264 # Files that #define IGNORE_EINTR.
265 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
266 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
267 ),
268 ),
[email protected]ec5b3f02014-04-04 18:43:43269 (
270 r'/v8::Extension\(',
271 (
272 'Do not introduce new v8::Extensions into the code base, use',
273 'gin::Wrappable instead. See http://crbug.com/334679',
274 ),
275 True,
[email protected]f55c90ee62014-04-12 00:50:03276 (
joaodasilva718f87672014-08-30 09:25:49277 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03278 ),
[email protected]ec5b3f02014-04-04 18:43:43279 ),
skyostilf9469f72015-04-20 10:38:52280 (
jame2d1a952016-04-02 00:27:10281 '#pragma comment(lib,',
282 (
283 'Specify libraries to link with in build files and not in the source.',
284 ),
285 True,
286 (),
287 ),
[email protected]127f18ec2012-06-16 05:05:59288)
289
wnwenbdc444e2016-05-25 13:44:15290
mlamouria82272622014-09-16 18:45:04291_IPC_ENUM_TRAITS_DEPRECATED = (
292 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
293 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
294
[email protected]127f18ec2012-06-16 05:05:59295
[email protected]b00342e7f2013-03-26 16:21:54296_VALID_OS_MACROS = (
297 # Please keep sorted.
298 'OS_ANDROID',
299 'OS_BSD',
300 'OS_CAT', # For testing.
301 'OS_CHROMEOS',
302 'OS_FREEBSD',
303 'OS_IOS',
304 'OS_LINUX',
305 'OS_MACOSX',
306 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21307 'OS_NACL_NONSFI',
308 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54309 'OS_OPENBSD',
310 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37311 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54312 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54313 'OS_WIN',
314)
315
316
agrievef32bcc72016-04-04 14:57:40317_ANDROID_SPECIFIC_PYDEPS_FILES = [
318 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19319 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40320]
321
wnwenbdc444e2016-05-25 13:44:15322
agrievef32bcc72016-04-04 14:57:40323_GENERIC_PYDEPS_FILES = [
324 'build/secondary/tools/swarming_client/isolate.pydeps',
325]
326
wnwenbdc444e2016-05-25 13:44:15327
agrievef32bcc72016-04-04 14:57:40328_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
329
330
[email protected]55459852011-08-10 15:17:19331def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
332 """Attempts to prevent use of functions intended only for testing in
333 non-testing code. For now this is just a best-effort implementation
334 that ignores header files and may have some false positives. A
335 better implementation would probably need a proper C++ parser.
336 """
337 # We only scan .cc files and the like, as the declaration of
338 # for-testing functions in header files are hard to distinguish from
339 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44340 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19341
jochenc0d4808c2015-07-27 09:25:42342 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19343 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09344 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19345 exclusion_pattern = input_api.re.compile(
346 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
347 base_function_pattern, base_function_pattern))
348
349 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44350 black_list = (_EXCLUDED_PATHS +
351 _TEST_CODE_EXCLUDED_PATHS +
352 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19353 return input_api.FilterSourceFile(
354 affected_file,
355 white_list=(file_inclusion_pattern, ),
356 black_list=black_list)
357
358 problems = []
359 for f in input_api.AffectedSourceFiles(FilterFile):
360 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24361 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03362 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46363 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03364 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19365 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03366 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19367
368 if problems:
[email protected]f7051d52013-04-02 18:31:42369 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03370 else:
371 return []
[email protected]55459852011-08-10 15:17:19372
373
[email protected]10689ca2011-09-02 02:31:54374def _CheckNoIOStreamInHeaders(input_api, output_api):
375 """Checks to make sure no .h files include <iostream>."""
376 files = []
377 pattern = input_api.re.compile(r'^#include\s*<iostream>',
378 input_api.re.MULTILINE)
379 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
380 if not f.LocalPath().endswith('.h'):
381 continue
382 contents = input_api.ReadFile(f)
383 if pattern.search(contents):
384 files.append(f)
385
386 if len(files):
yolandyandaabc6d2016-04-18 18:29:39387 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06388 'Do not #include <iostream> in header files, since it inserts static '
389 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54390 '#include <ostream>. See http://crbug.com/94794',
391 files) ]
392 return []
393
394
[email protected]72df4e782012-06-21 16:28:18395def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52396 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18397 problems = []
398 for f in input_api.AffectedFiles():
399 if (not f.LocalPath().endswith(('.cc', '.mm'))):
400 continue
401
402 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04403 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18404 problems.append(' %s:%d' % (f.LocalPath(), line_num))
405
406 if not problems:
407 return []
408 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
409 '\n'.join(problems))]
410
411
danakj61c1aa22015-10-26 19:55:52412def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
413 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
414 errors = []
415 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
416 input_api.re.MULTILINE)
417 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
418 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
419 continue
420 for lnum, line in f.ChangedContents():
421 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17422 errors.append(output_api.PresubmitError(
423 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
424 'DCHECK_IS_ON()", not forgetting the braces.')
425 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52426 return errors
427
428
mcasasb7440c282015-02-04 14:52:19429def _FindHistogramNameInLine(histogram_name, line):
430 """Tries to find a histogram name or prefix in a line."""
431 if not "affected-histogram" in line:
432 return histogram_name in line
433 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
434 # the histogram_name.
435 if not '"' in line:
436 return False
437 histogram_prefix = line.split('\"')[1]
438 return histogram_prefix in histogram_name
439
440
441def _CheckUmaHistogramChanges(input_api, output_api):
442 """Check that UMA histogram names in touched lines can still be found in other
443 lines of the patch or in histograms.xml. Note that this check would not catch
444 the reverse: changes in histograms.xml not matched in the code itself."""
445 touched_histograms = []
446 histograms_xml_modifications = []
447 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
448 for f in input_api.AffectedFiles():
449 # If histograms.xml itself is modified, keep the modified lines for later.
450 if f.LocalPath().endswith(('histograms.xml')):
451 histograms_xml_modifications = f.ChangedContents()
452 continue
453 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
454 continue
455 for line_num, line in f.ChangedContents():
456 found = pattern.search(line)
457 if found:
458 touched_histograms.append([found.group(1), f, line_num])
459
460 # Search for the touched histogram names in the local modifications to
461 # histograms.xml, and, if not found, on the base histograms.xml file.
462 unmatched_histograms = []
463 for histogram_info in touched_histograms:
464 histogram_name_found = False
465 for line_num, line in histograms_xml_modifications:
466 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
467 if histogram_name_found:
468 break
469 if not histogram_name_found:
470 unmatched_histograms.append(histogram_info)
471
eromanb90c82e7e32015-04-01 15:13:49472 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19473 problems = []
474 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49475 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19476 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45477 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19478 histogram_name_found = False
479 for line in histograms_xml:
480 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
481 if histogram_name_found:
482 break
483 if not histogram_name_found:
484 problems.append(' [%s:%d] %s' %
485 (f.LocalPath(), line_num, histogram_name))
486
487 if not problems:
488 return []
489 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
490 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49491 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19492
wnwenbdc444e2016-05-25 13:44:15493
yolandyandaabc6d2016-04-18 18:29:39494def _CheckFlakyTestUsage(input_api, output_api):
495 """Check that FlakyTest annotation is our own instead of the android one"""
496 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
497 files = []
498 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
499 if f.LocalPath().endswith('Test.java'):
500 if pattern.search(input_api.ReadFile(f)):
501 files.append(f)
502 if len(files):
503 return [output_api.PresubmitError(
504 'Use org.chromium.base.test.util.FlakyTest instead of '
505 'android.test.FlakyTest',
506 files)]
507 return []
mcasasb7440c282015-02-04 14:52:19508
wnwenbdc444e2016-05-25 13:44:15509
[email protected]8ea5d4b2011-09-13 21:49:22510def _CheckNoNewWStrings(input_api, output_api):
511 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27512 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22513 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20514 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57515 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34516 '/win/' in f.LocalPath() or
517 'chrome_elf' in f.LocalPath() or
518 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20519 continue
[email protected]8ea5d4b2011-09-13 21:49:22520
[email protected]a11dbe9b2012-08-07 01:32:58521 allowWString = False
[email protected]b5c24292011-11-28 14:38:20522 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58523 if 'presubmit: allow wstring' in line:
524 allowWString = True
525 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27526 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58527 allowWString = False
528 else:
529 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22530
[email protected]55463aa62011-10-12 00:48:27531 if not problems:
532 return []
533 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58534 ' If you are calling a cross-platform API that accepts a wstring, '
535 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27536 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22537
538
[email protected]2a8ac9c2011-10-19 17:20:44539def _CheckNoDEPSGIT(input_api, output_api):
540 """Make sure .DEPS.git is never modified manually."""
541 if any(f.LocalPath().endswith('.DEPS.git') for f in
542 input_api.AffectedFiles()):
543 return [output_api.PresubmitError(
544 'Never commit changes to .DEPS.git. This file is maintained by an\n'
545 'automated system based on what\'s in DEPS and your changes will be\n'
546 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34547 '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:44548 'for more information')]
549 return []
550
551
tandriief664692014-09-23 14:51:47552def _CheckValidHostsInDEPS(input_api, output_api):
553 """Checks that DEPS file deps are from allowed_hosts."""
554 # Run only if DEPS file has been modified to annoy fewer bystanders.
555 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
556 return []
557 # Outsource work to gclient verify
558 try:
559 input_api.subprocess.check_output(['gclient', 'verify'])
560 return []
561 except input_api.subprocess.CalledProcessError, error:
562 return [output_api.PresubmitError(
563 'DEPS file must have only git dependencies.',
564 long_text=error.output)]
565
566
[email protected]127f18ec2012-06-16 05:05:59567def _CheckNoBannedFunctions(input_api, output_api):
568 """Make sure that banned functions are not used."""
569 warnings = []
570 errors = []
571
wnwenbdc444e2016-05-25 13:44:15572 def IsBlacklisted(affected_file, blacklist):
573 local_path = affected_file.LocalPath()
574 for item in blacklist:
575 if input_api.re.match(item, local_path):
576 return True
577 return False
578
579 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
580 matched = False
581 if func_name[0:1] == '/':
582 regex = func_name[1:]
583 if input_api.re.search(regex, line):
584 matched = True
585 elif func_name in line:
dchenge07de812016-06-20 19:27:17586 matched = True
wnwenbdc444e2016-05-25 13:44:15587 if matched:
dchenge07de812016-06-20 19:27:17588 problems = warnings
wnwenbdc444e2016-05-25 13:44:15589 if error:
dchenge07de812016-06-20 19:27:17590 problems = errors
wnwenbdc444e2016-05-25 13:44:15591 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
592 for message_line in message:
593 problems.append(' %s' % message_line)
594
[email protected]127f18ec2012-06-16 05:05:59595 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
596 for f in input_api.AffectedFiles(file_filter=file_filter):
597 for line_num, line in f.ChangedContents():
598 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15599 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59600
601 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
602 for f in input_api.AffectedFiles(file_filter=file_filter):
603 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49604 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49605 if IsBlacklisted(f, excluded_paths):
606 continue
wnwenbdc444e2016-05-25 13:44:15607 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59608
609 result = []
610 if (warnings):
611 result.append(output_api.PresubmitPromptWarning(
612 'Banned functions were used.\n' + '\n'.join(warnings)))
613 if (errors):
614 result.append(output_api.PresubmitError(
615 'Banned functions were used.\n' + '\n'.join(errors)))
616 return result
617
618
[email protected]6c063c62012-07-11 19:11:06619def _CheckNoPragmaOnce(input_api, output_api):
620 """Make sure that banned functions are not used."""
621 files = []
622 pattern = input_api.re.compile(r'^#pragma\s+once',
623 input_api.re.MULTILINE)
624 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
625 if not f.LocalPath().endswith('.h'):
626 continue
627 contents = input_api.ReadFile(f)
628 if pattern.search(contents):
629 files.append(f)
630
631 if files:
632 return [output_api.PresubmitError(
633 'Do not use #pragma once in header files.\n'
634 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
635 files)]
636 return []
637
[email protected]127f18ec2012-06-16 05:05:59638
[email protected]e7479052012-09-19 00:26:12639def _CheckNoTrinaryTrueFalse(input_api, output_api):
640 """Checks to make sure we don't introduce use of foo ? true : false."""
641 problems = []
642 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
643 for f in input_api.AffectedFiles():
644 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
645 continue
646
647 for line_num, line in f.ChangedContents():
648 if pattern.match(line):
649 problems.append(' %s:%d' % (f.LocalPath(), line_num))
650
651 if not problems:
652 return []
653 return [output_api.PresubmitPromptWarning(
654 'Please consider avoiding the "? true : false" pattern if possible.\n' +
655 '\n'.join(problems))]
656
657
[email protected]55f9f382012-07-31 11:02:18658def _CheckUnwantedDependencies(input_api, output_api):
659 """Runs checkdeps on #include statements added in this
660 change. Breaking - rules is an error, breaking ! rules is a
661 warning.
662 """
mohan.reddyf21db962014-10-16 12:26:47663 import sys
[email protected]55f9f382012-07-31 11:02:18664 # We need to wait until we have an input_api object and use this
665 # roundabout construct to import checkdeps because this file is
666 # eval-ed and thus doesn't have __file__.
667 original_sys_path = sys.path
668 try:
669 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47670 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18671 import checkdeps
672 from cpp_checker import CppChecker
673 from rules import Rule
674 finally:
675 # Restore sys.path to what it was before.
676 sys.path = original_sys_path
677
678 added_includes = []
679 for f in input_api.AffectedFiles():
680 if not CppChecker.IsCppFile(f.LocalPath()):
681 continue
682
683 changed_lines = [line for line_num, line in f.ChangedContents()]
684 added_includes.append([f.LocalPath(), changed_lines])
685
[email protected]26385172013-05-09 23:11:35686 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18687
688 error_descriptions = []
689 warning_descriptions = []
690 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
691 added_includes):
692 description_with_path = '%s\n %s' % (path, rule_description)
693 if rule_type == Rule.DISALLOW:
694 error_descriptions.append(description_with_path)
695 else:
696 warning_descriptions.append(description_with_path)
697
698 results = []
699 if error_descriptions:
700 results.append(output_api.PresubmitError(
701 'You added one or more #includes that violate checkdeps rules.',
702 error_descriptions))
703 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42704 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18705 'You added one or more #includes of files that are temporarily\n'
706 'allowed but being removed. Can you avoid introducing the\n'
707 '#include? See relevant DEPS file(s) for details and contacts.',
708 warning_descriptions))
709 return results
710
711
[email protected]fbcafe5a2012-08-08 15:31:22712def _CheckFilePermissions(input_api, output_api):
713 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15714 if input_api.platform == 'win32':
715 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29716 checkperms_tool = input_api.os_path.join(
717 input_api.PresubmitLocalPath(),
718 'tools', 'checkperms', 'checkperms.py')
719 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47720 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22721 for f in input_api.AffectedFiles():
722 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11723 try:
724 input_api.subprocess.check_output(args)
725 return []
726 except input_api.subprocess.CalledProcessError as error:
727 return [output_api.PresubmitError(
728 'checkperms.py failed:',
729 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22730
731
[email protected]c8278b32012-10-30 20:35:49732def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
733 """Makes sure we don't include ui/aura/window_property.h
734 in header files.
735 """
736 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
737 errors = []
738 for f in input_api.AffectedFiles():
739 if not f.LocalPath().endswith('.h'):
740 continue
741 for line_num, line in f.ChangedContents():
742 if pattern.match(line):
743 errors.append(' %s:%d' % (f.LocalPath(), line_num))
744
745 results = []
746 if errors:
747 results.append(output_api.PresubmitError(
748 'Header files should not include ui/aura/window_property.h', errors))
749 return results
750
751
[email protected]cf9b78f2012-11-14 11:40:28752def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
753 """Checks that the lines in scope occur in the right order.
754
755 1. C system files in alphabetical order
756 2. C++ system files in alphabetical order
757 3. Project's .h files
758 """
759
760 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
761 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
762 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
763
764 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
765
766 state = C_SYSTEM_INCLUDES
767
768 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57769 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28770 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55771 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28772 for line_num, line in scope:
773 if c_system_include_pattern.match(line):
774 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55775 problem_linenums.append((line_num, previous_line_num,
776 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28777 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55778 problem_linenums.append((line_num, previous_line_num,
779 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28780 elif cpp_system_include_pattern.match(line):
781 if state == C_SYSTEM_INCLUDES:
782 state = CPP_SYSTEM_INCLUDES
783 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55784 problem_linenums.append((line_num, previous_line_num,
785 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28786 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55787 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28788 elif custom_include_pattern.match(line):
789 if state != CUSTOM_INCLUDES:
790 state = CUSTOM_INCLUDES
791 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55792 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28793 else:
brucedawson70fadb02015-06-30 17:47:55794 problem_linenums.append((line_num, previous_line_num,
795 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28796 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57797 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28798
799 warnings = []
brucedawson70fadb02015-06-30 17:47:55800 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57801 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55802 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28803 return warnings
804
805
[email protected]ac294a12012-12-06 16:38:43806def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28807 """Checks the #include order for the given file f."""
808
[email protected]2299dcf2012-11-15 19:56:24809 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30810 # Exclude the following includes from the check:
811 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
812 # specific order.
813 # 2) <atlbase.h>, "build/build_config.h"
814 excluded_include_pattern = input_api.re.compile(
815 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24816 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33817 # Match the final or penultimate token if it is xxxtest so we can ignore it
818 # when considering the special first include.
819 test_file_tag_pattern = input_api.re.compile(
820 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11821 if_pattern = input_api.re.compile(
822 r'\s*#\s*(if|elif|else|endif|define|undef).*')
823 # Some files need specialized order of includes; exclude such files from this
824 # check.
825 uncheckable_includes_pattern = input_api.re.compile(
826 r'\s*#include '
827 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28828
829 contents = f.NewContents()
830 warnings = []
831 line_num = 0
832
[email protected]ac294a12012-12-06 16:38:43833 # Handle the special first include. If the first include file is
834 # some/path/file.h, the corresponding including file can be some/path/file.cc,
835 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
836 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33837 # If the included file is some/path/file_platform.h the including file could
838 # also be some/path/file_xxxtest_platform.h.
839 including_file_base_name = test_file_tag_pattern.sub(
840 '', input_api.os_path.basename(f.LocalPath()))
841
[email protected]ac294a12012-12-06 16:38:43842 for line in contents:
843 line_num += 1
844 if system_include_pattern.match(line):
845 # No special first include -> process the line again along with normal
846 # includes.
847 line_num -= 1
848 break
849 match = custom_include_pattern.match(line)
850 if match:
851 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33852 header_basename = test_file_tag_pattern.sub(
853 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
854
855 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24856 # No special first include -> process the line again along with normal
857 # includes.
858 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43859 break
[email protected]cf9b78f2012-11-14 11:40:28860
861 # Split into scopes: Each region between #if and #endif is its own scope.
862 scopes = []
863 current_scope = []
864 for line in contents[line_num:]:
865 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11866 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54867 continue
[email protected]2309b0fa02012-11-16 12:18:27868 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28869 scopes.append(current_scope)
870 current_scope = []
[email protected]962f117e2012-11-22 18:11:56871 elif ((system_include_pattern.match(line) or
872 custom_include_pattern.match(line)) and
873 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28874 current_scope.append((line_num, line))
875 scopes.append(current_scope)
876
877 for scope in scopes:
878 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
879 changed_linenums))
880 return warnings
881
882
883def _CheckIncludeOrder(input_api, output_api):
884 """Checks that the #include order is correct.
885
886 1. The corresponding header for source files.
887 2. C system files in alphabetical order
888 3. C++ system files in alphabetical order
889 4. Project's .h files in alphabetical order
890
[email protected]ac294a12012-12-06 16:38:43891 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
892 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28893 """
[email protected]e120b012014-08-15 19:08:35894 def FileFilterIncludeOrder(affected_file):
895 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
896 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28897
898 warnings = []
[email protected]e120b012014-08-15 19:08:35899 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08900 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43901 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
902 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28903
904 results = []
905 if warnings:
[email protected]f7051d52013-04-02 18:31:42906 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53907 warnings))
[email protected]cf9b78f2012-11-14 11:40:28908 return results
909
910
[email protected]70ca77752012-11-20 03:45:03911def _CheckForVersionControlConflictsInFile(input_api, f):
912 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
913 errors = []
914 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23915 if f.LocalPath().endswith('.md'):
916 # First-level headers in markdown look a lot like version control
917 # conflict markers. http://daringfireball.net/projects/markdown/basics
918 continue
[email protected]70ca77752012-11-20 03:45:03919 if pattern.match(line):
920 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
921 return errors
922
923
924def _CheckForVersionControlConflicts(input_api, output_api):
925 """Usually this is not intentional and will cause a compile failure."""
926 errors = []
927 for f in input_api.AffectedFiles():
928 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
929
930 results = []
931 if errors:
932 results.append(output_api.PresubmitError(
933 'Version control conflict markers found, please resolve.', errors))
934 return results
935
936
[email protected]06e6d0ff2012-12-11 01:36:44937def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
938 def FilterFile(affected_file):
939 """Filter function for use with input_api.AffectedSourceFiles,
940 below. This filters out everything except non-test files from
941 top-level directories that generally speaking should not hard-code
942 service URLs (e.g. src/android_webview/, src/content/ and others).
943 """
944 return input_api.FilterSourceFile(
945 affected_file,
[email protected]78bb39d62012-12-11 15:11:56946 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44947 black_list=(_EXCLUDED_PATHS +
948 _TEST_CODE_EXCLUDED_PATHS +
949 input_api.DEFAULT_BLACK_LIST))
950
reillyi38965732015-11-16 18:27:33951 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
952 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46953 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
954 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44955 problems = [] # items are (filename, line_number, line)
956 for f in input_api.AffectedSourceFiles(FilterFile):
957 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46958 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44959 problems.append((f.LocalPath(), line_num, line))
960
961 if problems:
[email protected]f7051d52013-04-02 18:31:42962 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44963 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58964 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44965 [' %s:%d: %s' % (
966 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03967 else:
968 return []
[email protected]06e6d0ff2012-12-11 01:36:44969
970
[email protected]d2530012013-01-25 16:39:27971def _CheckNoAbbreviationInPngFileName(input_api, output_api):
972 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31973 The native_client_sdk directory is excluded because it has auto-generated PNG
974 files for documentation.
[email protected]d2530012013-01-25 16:39:27975 """
[email protected]d2530012013-01-25 16:39:27976 errors = []
binji0dcdf342014-12-12 18:32:31977 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
978 black_list = (r'^native_client_sdk[\\\/]',)
979 file_filter = lambda f: input_api.FilterSourceFile(
980 f, white_list=white_list, black_list=black_list)
981 for f in input_api.AffectedFiles(include_deletes=False,
982 file_filter=file_filter):
983 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27984
985 results = []
986 if errors:
987 results.append(output_api.PresubmitError(
988 'The name of PNG files should not have abbreviations. \n'
989 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
990 'Contact [email protected] if you have questions.', errors))
991 return results
992
993
[email protected]14a6131c2014-01-08 01:15:41994def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08995 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41996 a set of DEPS entries that we should look up.
997
998 For a directory (rather than a specific filename) we fake a path to
999 a specific filename by adding /DEPS. This is chosen as a file that
1000 will seldom or never be subject to per-file include_rules.
1001 """
[email protected]2b438d62013-11-14 17:54:141002 # We ignore deps entries on auto-generated directories.
1003 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081004
1005 # This pattern grabs the path without basename in the first
1006 # parentheses, and the basename (if present) in the second. It
1007 # relies on the simple heuristic that if there is a basename it will
1008 # be a header file ending in ".h".
1009 pattern = re.compile(
1010 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141011 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081012 for changed_line in changed_lines:
1013 m = pattern.match(changed_line)
1014 if m:
1015 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141016 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411017 if m.group(2):
1018 results.add('%s%s' % (path, m.group(2)))
1019 else:
1020 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081021 return results
1022
1023
[email protected]e871964c2013-05-13 14:14:551024def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1025 """When a dependency prefixed with + is added to a DEPS file, we
1026 want to make sure that the change is reviewed by an OWNER of the
1027 target file or directory, to avoid layering violations from being
1028 introduced. This check verifies that this happens.
1029 """
1030 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241031
1032 file_filter = lambda f: not input_api.re.match(
1033 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1034 for f in input_api.AffectedFiles(include_deletes=False,
1035 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551036 filename = input_api.os_path.basename(f.LocalPath())
1037 if filename == 'DEPS':
1038 changed_lines |= set(line.strip()
1039 for line_num, line
1040 in f.ChangedContents())
1041 if not changed_lines:
1042 return []
1043
[email protected]14a6131c2014-01-08 01:15:411044 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1045 changed_lines)
[email protected]e871964c2013-05-13 14:14:551046 if not virtual_depended_on_files:
1047 return []
1048
1049 if input_api.is_committing:
1050 if input_api.tbr:
1051 return [output_api.PresubmitNotifyResult(
1052 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271053 if input_api.dry_run:
1054 return [output_api.PresubmitNotifyResult(
1055 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551056 if not input_api.change.issue:
1057 return [output_api.PresubmitError(
1058 "DEPS approval by OWNERS check failed: this change has "
1059 "no Rietveld issue number, so we can't check it for approvals.")]
1060 output = output_api.PresubmitError
1061 else:
1062 output = output_api.PresubmitNotifyResult
1063
1064 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501065 owner_email, reviewers = (
1066 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1067 input_api,
1068 owners_db.email_regexp,
1069 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551070
1071 owner_email = owner_email or input_api.change.author_email
1072
[email protected]de4f7d22013-05-23 14:27:461073 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511074 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461075 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551076 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1077 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411078
1079 # We strip the /DEPS part that was added by
1080 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1081 # directory.
1082 def StripDeps(path):
1083 start_deps = path.rfind('/DEPS')
1084 if start_deps != -1:
1085 return path[:start_deps]
1086 else:
1087 return path
1088 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551089 for path in missing_files]
1090
1091 if unapproved_dependencies:
1092 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151093 output('You need LGTM from owners of depends-on paths in DEPS that were '
1094 'modified in this CL:\n %s' %
1095 '\n '.join(sorted(unapproved_dependencies)))]
1096 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1097 output_list.append(output(
1098 'Suggested missing target path OWNERS:\n %s' %
1099 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551100 return output_list
1101
1102 return []
1103
1104
[email protected]85218562013-11-22 07:41:401105def _CheckSpamLogging(input_api, output_api):
1106 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1107 black_list = (_EXCLUDED_PATHS +
1108 _TEST_CODE_EXCLUDED_PATHS +
1109 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501110 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191111 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481112 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461113 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121114 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1115 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581116 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161117 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031118 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151119 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1120 r"^chromecast[\\\/]",
1121 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311122 r"^components[\\\/]html_viewer[\\\/]"
1123 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461124 # TODO(peter): Remove this exception. https://crbug.com/534537
1125 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1126 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251127 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1128 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241129 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111130 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151131 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111132 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521133 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501134 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361135 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311136 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131137 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441138 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451139 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021140 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441141 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401142 source_file_filter = lambda x: input_api.FilterSourceFile(
1143 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1144
1145 log_info = []
1146 printf = []
1147
1148 for f in input_api.AffectedSourceFiles(source_file_filter):
1149 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471150 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401151 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471152 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131153 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371154
mohan.reddyf21db962014-10-16 12:26:471155 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371156 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471157 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401158 printf.append(f.LocalPath())
1159
1160 if log_info:
1161 return [output_api.PresubmitError(
1162 'These files spam the console log with LOG(INFO):',
1163 items=log_info)]
1164 if printf:
1165 return [output_api.PresubmitError(
1166 'These files spam the console log with printf/fprintf:',
1167 items=printf)]
1168 return []
1169
1170
[email protected]49aa76a2013-12-04 06:59:161171def _CheckForAnonymousVariables(input_api, output_api):
1172 """These types are all expected to hold locks while in scope and
1173 so should never be anonymous (which causes them to be immediately
1174 destroyed)."""
1175 they_who_must_be_named = [
1176 'base::AutoLock',
1177 'base::AutoReset',
1178 'base::AutoUnlock',
1179 'SkAutoAlphaRestore',
1180 'SkAutoBitmapShaderInstall',
1181 'SkAutoBlitterChoose',
1182 'SkAutoBounderCommit',
1183 'SkAutoCallProc',
1184 'SkAutoCanvasRestore',
1185 'SkAutoCommentBlock',
1186 'SkAutoDescriptor',
1187 'SkAutoDisableDirectionCheck',
1188 'SkAutoDisableOvalCheck',
1189 'SkAutoFree',
1190 'SkAutoGlyphCache',
1191 'SkAutoHDC',
1192 'SkAutoLockColors',
1193 'SkAutoLockPixels',
1194 'SkAutoMalloc',
1195 'SkAutoMaskFreeImage',
1196 'SkAutoMutexAcquire',
1197 'SkAutoPathBoundsUpdate',
1198 'SkAutoPDFRelease',
1199 'SkAutoRasterClipValidate',
1200 'SkAutoRef',
1201 'SkAutoTime',
1202 'SkAutoTrace',
1203 'SkAutoUnref',
1204 ]
1205 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1206 # bad: base::AutoLock(lock.get());
1207 # not bad: base::AutoLock lock(lock.get());
1208 bad_pattern = input_api.re.compile(anonymous)
1209 # good: new base::AutoLock(lock.get())
1210 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1211 errors = []
1212
1213 for f in input_api.AffectedFiles():
1214 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1215 continue
1216 for linenum, line in f.ChangedContents():
1217 if bad_pattern.search(line) and not good_pattern.search(line):
1218 errors.append('%s:%d' % (f.LocalPath(), linenum))
1219
1220 if errors:
1221 return [output_api.PresubmitError(
1222 'These lines create anonymous variables that need to be named:',
1223 items=errors)]
1224 return []
1225
1226
[email protected]5fe0f8742013-11-29 01:04:591227def _CheckCygwinShell(input_api, output_api):
1228 source_file_filter = lambda x: input_api.FilterSourceFile(
1229 x, white_list=(r'.+\.(gyp|gypi)$',))
1230 cygwin_shell = []
1231
1232 for f in input_api.AffectedSourceFiles(source_file_filter):
1233 for linenum, line in f.ChangedContents():
1234 if 'msvs_cygwin_shell' in line:
1235 cygwin_shell.append(f.LocalPath())
1236 break
1237
1238 if cygwin_shell:
1239 return [output_api.PresubmitError(
1240 'These files should not use msvs_cygwin_shell (the default is 0):',
1241 items=cygwin_shell)]
1242 return []
1243
[email protected]85218562013-11-22 07:41:401244
[email protected]999261d2014-03-03 20:08:081245def _CheckUserActionUpdate(input_api, output_api):
1246 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521247 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081248 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521249 # If actions.xml is already included in the changelist, the PRESUBMIT
1250 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081251 return []
1252
[email protected]999261d2014-03-03 20:08:081253 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1254 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521255 current_actions = None
[email protected]999261d2014-03-03 20:08:081256 for f in input_api.AffectedFiles(file_filter=file_filter):
1257 for line_num, line in f.ChangedContents():
1258 match = input_api.re.search(action_re, line)
1259 if match:
[email protected]2f92dec2014-03-07 19:21:521260 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1261 # loaded only once.
1262 if not current_actions:
1263 with open('tools/metrics/actions/actions.xml') as actions_f:
1264 current_actions = actions_f.read()
1265 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081266 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521267 action = 'name="{0}"'.format(action_name)
1268 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081269 return [output_api.PresubmitPromptWarning(
1270 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521271 'tools/metrics/actions/actions.xml. Please run '
1272 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081273 % (f.LocalPath(), line_num, action_name))]
1274 return []
1275
1276
[email protected]99171a92014-06-03 08:44:471277def _GetJSONParseError(input_api, filename, eat_comments=True):
1278 try:
1279 contents = input_api.ReadFile(filename)
1280 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131281 import sys
1282 original_sys_path = sys.path
1283 try:
1284 sys.path = sys.path + [input_api.os_path.join(
1285 input_api.PresubmitLocalPath(),
1286 'tools', 'json_comment_eater')]
1287 import json_comment_eater
1288 finally:
1289 sys.path = original_sys_path
1290 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471291
1292 input_api.json.loads(contents)
1293 except ValueError as e:
1294 return e
1295 return None
1296
1297
1298def _GetIDLParseError(input_api, filename):
1299 try:
1300 contents = input_api.ReadFile(filename)
1301 idl_schema = input_api.os_path.join(
1302 input_api.PresubmitLocalPath(),
1303 'tools', 'json_schema_compiler', 'idl_schema.py')
1304 process = input_api.subprocess.Popen(
1305 [input_api.python_executable, idl_schema],
1306 stdin=input_api.subprocess.PIPE,
1307 stdout=input_api.subprocess.PIPE,
1308 stderr=input_api.subprocess.PIPE,
1309 universal_newlines=True)
1310 (_, error) = process.communicate(input=contents)
1311 return error or None
1312 except ValueError as e:
1313 return e
1314
1315
1316def _CheckParseErrors(input_api, output_api):
1317 """Check that IDL and JSON files do not contain syntax errors."""
1318 actions = {
1319 '.idl': _GetIDLParseError,
1320 '.json': _GetJSONParseError,
1321 }
1322 # These paths contain test data and other known invalid JSON files.
1323 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491324 r'test[\\\/]data[\\\/]',
1325 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471326 ]
1327 # Most JSON files are preprocessed and support comments, but these do not.
1328 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491329 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471330 ]
1331 # Only run IDL checker on files in these directories.
1332 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491333 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1334 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471335 ]
1336
1337 def get_action(affected_file):
1338 filename = affected_file.LocalPath()
1339 return actions.get(input_api.os_path.splitext(filename)[1])
1340
1341 def MatchesFile(patterns, path):
1342 for pattern in patterns:
1343 if input_api.re.search(pattern, path):
1344 return True
1345 return False
1346
1347 def FilterFile(affected_file):
1348 action = get_action(affected_file)
1349 if not action:
1350 return False
1351 path = affected_file.LocalPath()
1352
1353 if MatchesFile(excluded_patterns, path):
1354 return False
1355
1356 if (action == _GetIDLParseError and
1357 not MatchesFile(idl_included_patterns, path)):
1358 return False
1359 return True
1360
1361 results = []
1362 for affected_file in input_api.AffectedFiles(
1363 file_filter=FilterFile, include_deletes=False):
1364 action = get_action(affected_file)
1365 kwargs = {}
1366 if (action == _GetJSONParseError and
1367 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1368 kwargs['eat_comments'] = False
1369 parse_error = action(input_api,
1370 affected_file.AbsoluteLocalPath(),
1371 **kwargs)
1372 if parse_error:
1373 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1374 (affected_file.LocalPath(), parse_error)))
1375 return results
1376
1377
[email protected]760deea2013-12-10 19:33:491378def _CheckJavaStyle(input_api, output_api):
1379 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471380 import sys
[email protected]760deea2013-12-10 19:33:491381 original_sys_path = sys.path
1382 try:
1383 sys.path = sys.path + [input_api.os_path.join(
1384 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1385 import checkstyle
1386 finally:
1387 # Restore sys.path to what it was before.
1388 sys.path = original_sys_path
1389
1390 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091391 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511392 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491393
1394
dchenge07de812016-06-20 19:27:171395def _CheckIpcOwners(input_api, output_api):
1396 """Checks that affected files involving IPC have an IPC OWNERS rule.
1397
1398 Whether or not a file affects IPC is determined by a simple whitelist of
1399 filename patterns."""
1400 file_patterns = [
1401 '*_messages.cc',
1402 '*_messages*.h',
1403 '*_param_traits*.*',
1404 '*.mojom',
1405 '*_struct_traits*.*',
1406 '*_type_converter*.*',
1407 # Blink uses a different file naming convention
1408 '*StructTraits*.*',
1409 '*TypeConverter*.*',
1410 ]
1411
1412 # Dictionary mapping an OWNERS file path to Patterns.
1413 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1414 # rules ) to a PatternEntry.
1415 # PatternEntry is a dictionary with two keys:
1416 # - 'files': the files that are matched by this pattern
1417 # - 'rules': the per-file rules needed for this pattern
1418 # For example, if we expect OWNERS file to contain rules for *.mojom and
1419 # *_struct_traits*.*, Patterns might look like this:
1420 # {
1421 # '*.mojom': {
1422 # 'files': ...,
1423 # 'rules': [
1424 # 'per-file *.mojom=set noparent',
1425 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1426 # ],
1427 # },
1428 # '*_struct_traits*.*': {
1429 # 'files': ...,
1430 # 'rules': [
1431 # 'per-file *_struct_traits*.*=set noparent',
1432 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1433 # ],
1434 # },
1435 # }
1436 to_check = {}
1437
1438 # Iterate through the affected files to see what we actually need to check
1439 # for. We should only nag patch authors about per-file rules if a file in that
1440 # directory would match that pattern. If a directory only contains *.mojom
1441 # files and no *_messages*.h files, we should only nag about rules for
1442 # *.mojom files.
rockot51249332016-06-23 16:32:251443 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171444 for pattern in file_patterns:
1445 if input_api.fnmatch.fnmatch(
1446 input_api.os_path.basename(f.LocalPath()), pattern):
1447 owners_file = input_api.os_path.join(
1448 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1449 if owners_file not in to_check:
1450 to_check[owners_file] = {}
1451 if pattern not in to_check[owners_file]:
1452 to_check[owners_file][pattern] = {
1453 'files': [],
1454 'rules': [
1455 'per-file %s=set noparent' % pattern,
1456 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1457 ]
1458 }
1459 to_check[owners_file][pattern]['files'].append(f)
1460 break
1461
1462 # Now go through the OWNERS files we collected, filtering out rules that are
1463 # already present in that OWNERS file.
1464 for owners_file, patterns in to_check.iteritems():
1465 try:
1466 with file(owners_file) as f:
1467 lines = set(f.read().splitlines())
1468 for entry in patterns.itervalues():
1469 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1470 ]
1471 except IOError:
1472 # No OWNERS file, so all the rules are definitely missing.
1473 continue
1474
1475 # All the remaining lines weren't found in OWNERS files, so emit an error.
1476 errors = []
1477 for owners_file, patterns in to_check.iteritems():
1478 missing_lines = []
1479 files = []
1480 for pattern, entry in patterns.iteritems():
1481 missing_lines.extend(entry['rules'])
1482 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1483 if missing_lines:
1484 errors.append(
1485 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1486 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1487
1488 results = []
1489 if errors:
vabrf5ce3bf92016-07-11 14:52:411490 if input_api.is_committing:
1491 output = output_api.PresubmitError
1492 else:
1493 output = output_api.PresubmitPromptWarning
1494 results.append(output(
dchenge07de812016-06-20 19:27:171495 'Found changes to IPC files without a security OWNER!',
1496 long_text='\n\n'.join(errors)))
1497
1498 return results
1499
1500
dskiba88634f4e2015-08-14 23:03:291501def _CheckAndroidToastUsage(input_api, output_api):
1502 """Checks that code uses org.chromium.ui.widget.Toast instead of
1503 android.widget.Toast (Chromium Toast doesn't force hardware
1504 acceleration on low-end devices, saving memory).
1505 """
1506 toast_import_pattern = input_api.re.compile(
1507 r'^import android\.widget\.Toast;$')
1508
1509 errors = []
1510
1511 sources = lambda affected_file: input_api.FilterSourceFile(
1512 affected_file,
1513 black_list=(_EXCLUDED_PATHS +
1514 _TEST_CODE_EXCLUDED_PATHS +
1515 input_api.DEFAULT_BLACK_LIST +
1516 (r'^chromecast[\\\/].*',
1517 r'^remoting[\\\/].*')),
1518 white_list=(r'.*\.java$',))
1519
1520 for f in input_api.AffectedSourceFiles(sources):
1521 for line_num, line in f.ChangedContents():
1522 if toast_import_pattern.search(line):
1523 errors.append("%s:%d" % (f.LocalPath(), line_num))
1524
1525 results = []
1526
1527 if errors:
1528 results.append(output_api.PresubmitError(
1529 'android.widget.Toast usage is detected. Android toasts use hardware'
1530 ' acceleration, and can be\ncostly on low-end devices. Please use'
1531 ' org.chromium.ui.widget.Toast instead.\n'
1532 'Contact [email protected] if you have any questions.',
1533 errors))
1534
1535 return results
1536
1537
dgnaa68d5e2015-06-10 10:08:221538def _CheckAndroidCrLogUsage(input_api, output_api):
1539 """Checks that new logs using org.chromium.base.Log:
1540 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511541 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221542 """
pkotwicza1dd0b002016-05-16 14:41:041543
1544 # Do not check format of logs in //chrome/android/webapk because
1545 # //chrome/android/webapk cannot depend on //base
1546 cr_log_check_excluded_paths = [
1547 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1548 ]
1549
dgnaa68d5e2015-06-10 10:08:221550 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121551 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1552 class_in_base_pattern = input_api.re.compile(
1553 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1554 has_some_log_import_pattern = input_api.re.compile(
1555 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221556 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121557 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221558 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511559 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221560 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221561
Vincent Scheib16d7b272015-09-15 18:09:071562 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221563 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041564 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1565 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121566
dgnaa68d5e2015-06-10 10:08:221567 tag_decl_errors = []
1568 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121569 tag_errors = []
dgn38736db2015-09-18 19:20:511570 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121571 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221572
1573 for f in input_api.AffectedSourceFiles(sources):
1574 file_content = input_api.ReadFile(f)
1575 has_modified_logs = False
1576
1577 # Per line checks
dgn87d9fb62015-06-12 09:15:121578 if (cr_log_import_pattern.search(file_content) or
1579 (class_in_base_pattern.search(file_content) and
1580 not has_some_log_import_pattern.search(file_content))):
1581 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221582 for line_num, line in f.ChangedContents():
1583
1584 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121585 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221586 if match:
1587 has_modified_logs = True
1588
1589 # Make sure it uses "TAG"
1590 if not match.group('tag') == 'TAG':
1591 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121592 else:
1593 # Report non cr Log function calls in changed lines
1594 for line_num, line in f.ChangedContents():
1595 if log_call_pattern.search(line):
1596 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221597
1598 # Per file checks
1599 if has_modified_logs:
1600 # Make sure the tag is using the "cr" prefix and is not too long
1601 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511602 tag_name = match.group('name') if match else None
1603 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221604 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511605 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221606 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511607 elif '.' in tag_name:
1608 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221609
1610 results = []
1611 if tag_decl_errors:
1612 results.append(output_api.PresubmitPromptWarning(
1613 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511614 '"private static final String TAG = "<package tag>".\n'
1615 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221616 tag_decl_errors))
1617
1618 if tag_length_errors:
1619 results.append(output_api.PresubmitError(
1620 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511621 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221622 tag_length_errors))
1623
1624 if tag_errors:
1625 results.append(output_api.PresubmitPromptWarning(
1626 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1627 tag_errors))
1628
dgn87d9fb62015-06-12 09:15:121629 if util_log_errors:
dgn4401aa52015-04-29 16:26:171630 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121631 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1632 util_log_errors))
1633
dgn38736db2015-09-18 19:20:511634 if tag_with_dot_errors:
1635 results.append(output_api.PresubmitPromptWarning(
1636 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1637 tag_with_dot_errors))
1638
dgn4401aa52015-04-29 16:26:171639 return results
1640
1641
agrieve7b6479d82015-10-07 14:24:221642def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1643 """Checks if MDPI assets are placed in a correct directory."""
1644 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1645 ('/res/drawable/' in f.LocalPath() or
1646 '/res/drawable-ldrtl/' in f.LocalPath()))
1647 errors = []
1648 for f in input_api.AffectedFiles(include_deletes=False,
1649 file_filter=file_filter):
1650 errors.append(' %s' % f.LocalPath())
1651
1652 results = []
1653 if errors:
1654 results.append(output_api.PresubmitError(
1655 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1656 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1657 '/res/drawable-ldrtl/.\n'
1658 'Contact [email protected] if you have questions.', errors))
1659 return results
1660
1661
agrievef32bcc72016-04-04 14:57:401662class PydepsChecker(object):
1663 def __init__(self, input_api, pydeps_files):
1664 self._file_cache = {}
1665 self._input_api = input_api
1666 self._pydeps_files = pydeps_files
1667
1668 def _LoadFile(self, path):
1669 """Returns the list of paths within a .pydeps file relative to //."""
1670 if path not in self._file_cache:
1671 with open(path) as f:
1672 self._file_cache[path] = f.read()
1673 return self._file_cache[path]
1674
1675 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1676 """Returns an interable of paths within the .pydep, relativized to //."""
1677 os_path = self._input_api.os_path
1678 pydeps_dir = os_path.dirname(pydeps_path)
1679 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1680 if not l.startswith('*'))
1681 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1682
1683 def _CreateFilesToPydepsMap(self):
1684 """Returns a map of local_path -> list_of_pydeps."""
1685 ret = {}
1686 for pydep_local_path in self._pydeps_files:
1687 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1688 ret.setdefault(path, []).append(pydep_local_path)
1689 return ret
1690
1691 def ComputeAffectedPydeps(self):
1692 """Returns an iterable of .pydeps files that might need regenerating."""
1693 affected_pydeps = set()
1694 file_to_pydeps_map = None
1695 for f in self._input_api.AffectedFiles(include_deletes=True):
1696 local_path = f.LocalPath()
1697 if local_path == 'DEPS':
1698 return self._pydeps_files
1699 elif local_path.endswith('.pydeps'):
1700 if local_path in self._pydeps_files:
1701 affected_pydeps.add(local_path)
1702 elif local_path.endswith('.py'):
1703 if file_to_pydeps_map is None:
1704 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1705 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1706 return affected_pydeps
1707
1708 def DetermineIfStale(self, pydeps_path):
1709 """Runs print_python_deps.py to see if the files is stale."""
1710 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1711 cmd = old_pydeps_data[1][1:].strip()
1712 new_pydeps_data = self._input_api.subprocess.check_output(
1713 cmd + ' --output ""', shell=True)
1714 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1715 return cmd
1716
1717
1718def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1719 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001720 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281721 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1722 # Mac, so skip it on other platforms.
1723 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001724 return []
agrievef32bcc72016-04-04 14:57:401725 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1726 is_android = input_api.os_path.exists('third_party/android_tools')
1727 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1728 results = []
1729 # First, check for new / deleted .pydeps.
1730 for f in input_api.AffectedFiles(include_deletes=True):
1731 if f.LocalPath().endswith('.pydeps'):
1732 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1733 results.append(output_api.PresubmitError(
1734 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1735 'remove %s' % f.LocalPath()))
1736 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1737 results.append(output_api.PresubmitError(
1738 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1739 'include %s' % f.LocalPath()))
1740
1741 if results:
1742 return results
1743
1744 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1745
1746 for pydep_path in checker.ComputeAffectedPydeps():
1747 try:
1748 cmd = checker.DetermineIfStale(pydep_path)
1749 if cmd:
1750 results.append(output_api.PresubmitError(
1751 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1752 (pydep_path, cmd)))
1753 except input_api.subprocess.CalledProcessError as error:
1754 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1755 long_text=error.output)]
1756
1757 return results
1758
1759
mnaganov9b9b1fe82014-12-11 16:30:361760def _CheckForCopyrightedCode(input_api, output_api):
1761 """Verifies that newly added code doesn't contain copyrighted material
1762 and is properly licensed under the standard Chromium license.
1763
1764 As there can be false positives, we maintain a whitelist file. This check
1765 also verifies that the whitelist file is up to date.
1766 """
1767 import sys
1768 original_sys_path = sys.path
1769 try:
1770 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221771 input_api.PresubmitLocalPath(), 'tools')]
1772 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361773 finally:
1774 # Restore sys.path to what it was before.
1775 sys.path = original_sys_path
1776
1777 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1778
1779
glidere61efad2015-02-18 17:39:431780def _CheckSingletonInHeaders(input_api, output_api):
1781 """Checks to make sure no header files have |Singleton<|."""
1782 def FileFilter(affected_file):
1783 # It's ok for base/memory/singleton.h to have |Singleton<|.
1784 black_list = (_EXCLUDED_PATHS +
1785 input_api.DEFAULT_BLACK_LIST +
1786 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1787 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1788
sergeyu34d21222015-09-16 00:11:441789 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431790 files = []
1791 for f in input_api.AffectedSourceFiles(FileFilter):
1792 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1793 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1794 contents = input_api.ReadFile(f)
1795 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241796 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431797 pattern.search(line)):
1798 files.append(f)
1799 break
1800
1801 if files:
yolandyandaabc6d2016-04-18 18:29:391802 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441803 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431804 'Please move them to an appropriate source file so that the ' +
1805 'template gets instantiated in a single compilation unit.',
1806 files) ]
1807 return []
1808
1809
dbeam37e8e7402016-02-10 22:58:201810def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1811 """Checks for old style compiled_resources.gyp files."""
1812 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1813
1814 added_compiled_resources = filter(is_compiled_resource, [
1815 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1816 ])
1817
1818 if not added_compiled_resources:
1819 return []
1820
1821 return [output_api.PresubmitError(
1822 "Found new compiled_resources.gyp files:\n%s\n\n"
1823 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551824 "please use compiled_resources2.gyp instead:\n"
1825 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1826 %
dbeam37e8e7402016-02-10 22:58:201827 "\n".join(added_compiled_resources))]
1828
1829
[email protected]fd20b902014-05-09 02:14:531830_DEPRECATED_CSS = [
1831 # Values
1832 ( "-webkit-box", "flex" ),
1833 ( "-webkit-inline-box", "inline-flex" ),
1834 ( "-webkit-flex", "flex" ),
1835 ( "-webkit-inline-flex", "inline-flex" ),
1836 ( "-webkit-min-content", "min-content" ),
1837 ( "-webkit-max-content", "max-content" ),
1838
1839 # Properties
1840 ( "-webkit-background-clip", "background-clip" ),
1841 ( "-webkit-background-origin", "background-origin" ),
1842 ( "-webkit-background-size", "background-size" ),
1843 ( "-webkit-box-shadow", "box-shadow" ),
1844
1845 # Functions
1846 ( "-webkit-gradient", "gradient" ),
1847 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1848 ( "-webkit-linear-gradient", "linear-gradient" ),
1849 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1850 ( "-webkit-radial-gradient", "radial-gradient" ),
1851 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1852]
1853
1854def _CheckNoDeprecatedCSS(input_api, output_api):
1855 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251856 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341857 documentation and iOS CSS for dom distiller
1858 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251859 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531860 results = []
dbeam070cfe62014-10-22 06:44:021861 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251862 black_list = (_EXCLUDED_PATHS +
1863 _TEST_CODE_EXCLUDED_PATHS +
1864 input_api.DEFAULT_BLACK_LIST +
1865 (r"^chrome/common/extensions/docs",
1866 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341867 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051868 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441869 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251870 r"^native_client_sdk"))
1871 file_filter = lambda f: input_api.FilterSourceFile(
1872 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531873 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1874 for line_num, line in fpath.ChangedContents():
1875 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021876 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531877 results.append(output_api.PresubmitError(
1878 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1879 (fpath.LocalPath(), line_num, deprecated_value, value)))
1880 return results
1881
mohan.reddyf21db962014-10-16 12:26:471882
dbeam070cfe62014-10-22 06:44:021883_DEPRECATED_JS = [
1884 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1885 ( "__defineGetter__", "Object.defineProperty" ),
1886 ( "__defineSetter__", "Object.defineProperty" ),
1887]
1888
1889def _CheckNoDeprecatedJS(input_api, output_api):
1890 """Make sure that we don't use deprecated JS in Chrome code."""
1891 results = []
1892 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1893 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1894 input_api.DEFAULT_BLACK_LIST)
1895 file_filter = lambda f: input_api.FilterSourceFile(
1896 f, white_list=file_inclusion_pattern, black_list=black_list)
1897 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1898 for lnum, line in fpath.ChangedContents():
1899 for (deprecated, replacement) in _DEPRECATED_JS:
1900 if deprecated in line:
1901 results.append(output_api.PresubmitError(
1902 "%s:%d: Use of deprecated JS %s, use %s instead" %
1903 (fpath.LocalPath(), lnum, deprecated, replacement)))
1904 return results
1905
1906
dgnaa68d5e2015-06-10 10:08:221907def _AndroidSpecificOnUploadChecks(input_api, output_api):
1908 """Groups checks that target android code."""
1909 results = []
dgnaa68d5e2015-06-10 10:08:221910 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221911 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291912 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221913 return results
1914
1915
[email protected]22c9bd72011-03-27 16:47:391916def _CommonChecks(input_api, output_api):
1917 """Checks common to both upload and commit."""
1918 results = []
1919 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381920 input_api, output_api,
1921 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461922 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191923 results.extend(
[email protected]760deea2013-12-10 19:33:491924 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541925 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181926 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521927 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221928 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441929 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591930 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061931 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121932 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181933 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221934 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491935 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271936 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031937 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491938 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441939 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271940 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541941 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441942 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391943 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551944 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041945 results.extend(
1946 input_api.canned_checks.CheckChangeHasNoTabs(
1947 input_api,
1948 output_api,
1949 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401950 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161951 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591952 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081953 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531954 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021955 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471956 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041957 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361958 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231959 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431960 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201961 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401962 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:151963 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:171964 results.extend(_CheckIpcOwners(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241965
1966 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1967 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1968 input_api, output_api,
1969 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381970 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391971 return results
[email protected]1f7b4172010-01-28 01:17:341972
[email protected]b337cb5b2011-01-23 21:24:051973
[email protected]66daa702011-05-28 14:41:461974def _CheckAuthorizedAuthor(input_api, output_api):
1975 """For non-googler/chromites committers, verify the author's email address is
1976 in AUTHORS.
1977 """
1978 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011979 if not author:
1980 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461981 return []
[email protected]c99663292011-05-31 19:46:081982 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461983 input_api.PresubmitLocalPath(), 'AUTHORS')
1984 valid_authors = (
1985 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1986 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181987 valid_authors = [item.group(1).lower() for item in valid_authors if item]
dchenge07de812016-06-20 19:27:171988 if not any(input_api.fnmatch.fnmatch(author.lower(), valid)
1989 for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231990 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461991 return [output_api.PresubmitPromptWarning(
1992 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1993 '\n'
1994 'http://www.chromium.org/developers/contributing-code and read the '
1995 '"Legal" section\n'
1996 'If you are a chromite, verify the contributor signed the CLA.') %
1997 author)]
1998 return []
1999
2000
[email protected]b8079ae4a2012-12-05 19:56:492001def _CheckPatchFiles(input_api, output_api):
2002 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2003 if f.LocalPath().endswith(('.orig', '.rej'))]
2004 if problems:
2005 return [output_api.PresubmitError(
2006 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032007 else:
2008 return []
[email protected]b8079ae4a2012-12-05 19:56:492009
2010
[email protected]b00342e7f2013-03-26 16:21:542011def _DidYouMeanOSMacro(bad_macro):
2012 try:
2013 return {'A': 'OS_ANDROID',
2014 'B': 'OS_BSD',
2015 'C': 'OS_CHROMEOS',
2016 'F': 'OS_FREEBSD',
2017 'L': 'OS_LINUX',
2018 'M': 'OS_MACOSX',
2019 'N': 'OS_NACL',
2020 'O': 'OS_OPENBSD',
2021 'P': 'OS_POSIX',
2022 'S': 'OS_SOLARIS',
2023 'W': 'OS_WIN'}[bad_macro[3].upper()]
2024 except KeyError:
2025 return ''
2026
2027
2028def _CheckForInvalidOSMacrosInFile(input_api, f):
2029 """Check for sensible looking, totally invalid OS macros."""
2030 preprocessor_statement = input_api.re.compile(r'^\s*#')
2031 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2032 results = []
2033 for lnum, line in f.ChangedContents():
2034 if preprocessor_statement.search(line):
2035 for match in os_macro.finditer(line):
2036 if not match.group(1) in _VALID_OS_MACROS:
2037 good = _DidYouMeanOSMacro(match.group(1))
2038 did_you_mean = ' (did you mean %s?)' % good if good else ''
2039 results.append(' %s:%d %s%s' % (f.LocalPath(),
2040 lnum,
2041 match.group(1),
2042 did_you_mean))
2043 return results
2044
2045
2046def _CheckForInvalidOSMacros(input_api, output_api):
2047 """Check all affected files for invalid OS macros."""
2048 bad_macros = []
2049 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472050 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542051 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2052
2053 if not bad_macros:
2054 return []
2055
2056 return [output_api.PresubmitError(
2057 'Possibly invalid OS macro[s] found. Please fix your code\n'
2058 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2059
lliabraa35bab3932014-10-01 12:16:442060
2061def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2062 """Check all affected files for invalid "if defined" macros."""
2063 ALWAYS_DEFINED_MACROS = (
2064 "TARGET_CPU_PPC",
2065 "TARGET_CPU_PPC64",
2066 "TARGET_CPU_68K",
2067 "TARGET_CPU_X86",
2068 "TARGET_CPU_ARM",
2069 "TARGET_CPU_MIPS",
2070 "TARGET_CPU_SPARC",
2071 "TARGET_CPU_ALPHA",
2072 "TARGET_IPHONE_SIMULATOR",
2073 "TARGET_OS_EMBEDDED",
2074 "TARGET_OS_IPHONE",
2075 "TARGET_OS_MAC",
2076 "TARGET_OS_UNIX",
2077 "TARGET_OS_WIN32",
2078 )
2079 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2080 results = []
2081 for lnum, line in f.ChangedContents():
2082 for match in ifdef_macro.finditer(line):
2083 if match.group(1) in ALWAYS_DEFINED_MACROS:
2084 always_defined = ' %s is always defined. ' % match.group(1)
2085 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2086 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2087 lnum,
2088 always_defined,
2089 did_you_mean))
2090 return results
2091
2092
2093def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2094 """Check all affected files for invalid "if defined" macros."""
2095 bad_macros = []
2096 for f in input_api.AffectedFiles():
2097 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2098 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2099
2100 if not bad_macros:
2101 return []
2102
2103 return [output_api.PresubmitError(
2104 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2105 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2106 bad_macros)]
2107
2108
mlamouria82272622014-09-16 18:45:042109def _CheckForIPCRules(input_api, output_api):
2110 """Check for same IPC rules described in
2111 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2112 """
2113 base_pattern = r'IPC_ENUM_TRAITS\('
2114 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2115 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2116
2117 problems = []
2118 for f in input_api.AffectedSourceFiles(None):
2119 local_path = f.LocalPath()
2120 if not local_path.endswith('.h'):
2121 continue
2122 for line_number, line in f.ChangedContents():
2123 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2124 problems.append(
2125 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2126
2127 if problems:
2128 return [output_api.PresubmitPromptWarning(
2129 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2130 else:
2131 return []
2132
[email protected]b00342e7f2013-03-26 16:21:542133
mostynbb639aca52015-01-07 20:31:232134def _CheckForWindowsLineEndings(input_api, output_api):
2135 """Check source code and known ascii text files for Windows style line
2136 endings.
2137 """
earthdok1b5e0ee2015-03-10 15:19:102138 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232139
2140 file_inclusion_pattern = (
2141 known_text_files,
2142 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2143 )
2144
2145 filter = lambda f: input_api.FilterSourceFile(
2146 f, white_list=file_inclusion_pattern, black_list=None)
2147 files = [f.LocalPath() for f in
2148 input_api.AffectedSourceFiles(filter)]
2149
2150 problems = []
2151
2152 for file in files:
2153 fp = open(file, 'r')
2154 for line in fp:
2155 if line.endswith('\r\n'):
2156 problems.append(file)
2157 break
2158 fp.close()
2159
2160 if problems:
2161 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2162 'these files to contain Windows style line endings?\n' +
2163 '\n'.join(problems))]
2164
2165 return []
2166
2167
[email protected]1f7b4172010-01-28 01:17:342168def CheckChangeOnUpload(input_api, output_api):
2169 results = []
2170 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472171 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282172 results.extend(
2173 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192174 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222175 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542176 return results
[email protected]ca8d19842009-02-19 16:33:122177
2178
[email protected]1bfb8322014-04-23 01:02:412179def GetTryServerMasterForBot(bot):
2180 """Returns the Try Server master for the given bot.
2181
[email protected]0bb112362014-07-26 04:38:322182 It tries to guess the master from the bot name, but may still fail
2183 and return None. There is no longer a default master.
2184 """
2185 # Potentially ambiguous bot names are listed explicitly.
2186 master_map = {
[email protected]0bb112362014-07-26 04:38:322187 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322188 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412189 }
[email protected]0bb112362014-07-26 04:38:322190 master = master_map.get(bot)
2191 if not master:
wnwen4fbaab82016-05-25 12:54:362192 if 'android' in bot:
2193 master = 'tryserver.chromium.android'
2194 elif 'linux' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322195 master = 'tryserver.chromium.linux'
2196 elif 'win' in bot:
2197 master = 'tryserver.chromium.win'
2198 elif 'mac' in bot or 'ios' in bot:
2199 master = 'tryserver.chromium.mac'
2200 return master
[email protected]1bfb8322014-04-23 01:02:412201
2202
Paweł Hajdan, Jr55083782014-12-19 20:32:562203def GetDefaultTryConfigs(bots):
2204 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012205 """
2206
Paweł Hajdan, Jr55083782014-12-19 20:32:562207 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412208
2209 # Build up the mapping from tryserver master to bot/test.
2210 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562211 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412212 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2213 return out
[email protected]38c6a512013-12-18 23:48:012214
2215
[email protected]ca8d19842009-02-19 16:33:122216def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542217 results = []
[email protected]1f7b4172010-01-28 01:17:342218 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542219 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272220 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342221 input_api,
2222 output_api,
[email protected]2fdd1f362013-01-16 03:56:032223 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272224
[email protected]3e4eb112011-01-18 03:29:542225 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2226 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412227 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2228 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542229 return results