blob: 7672a57ede6a43b87b8011450c6cd3a177bac01b [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d19842009-02-19 16:33:1227
jochen9ea8fdbc2014-09-25 13:21:3528# The NetscapePlugIn library is excluded from pan-project as it will soon
29# be deleted together with the rest of the NPAPI and it's not worthwhile to
30# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3831_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3232 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3833)
34
[email protected]06e6d0ff2012-12-11 01:36:4435# Fragment of a regular expression that matches C++ and Objective-C++
36# implementation files.
37_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
38
39# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3244 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4450 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4951 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4752 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4953 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0854 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4955 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4456)
[email protected]ca8d19842009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
nyad2c548b2015-12-09 03:22:32167 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10168 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49169 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22170 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31171 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51172 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
173 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09174 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49175 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
176 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41177 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
178 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48179 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
180 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01181 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54182 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13183 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
184 "gnubby_auth_handler_linux\.cc$",
dnicoara171d8c82015-03-05 20:46:18185 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
rjkroege8471a0a92016-02-04 19:50:29186 "drm_display_host_manager\.cc$",
tdanderson33686582016-05-06 22:40:08187 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
188 "material_design_controller\.cc$",
[email protected]7345da02012-11-27 14:31:49189 ),
[email protected]23e6cbc2012-06-16 18:51:20190 ),
[email protected]52657f62013-05-20 05:30:31191 (
tomhudson7e6e0512016-04-19 19:27:22192 'skia::RefPtr',
193 (
194 'The use of skia::RefPtr is prohibited. ',
195 'Please use sk_sp<> instead.'
196 ),
197 True,
198 (),
199 ),
200 (
[email protected]52657f62013-05-20 05:30:31201 'SkRefPtr',
202 (
203 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22204 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31205 ),
206 True,
207 (),
208 ),
209 (
210 'SkAutoRef',
211 (
212 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22213 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31214 ),
215 True,
216 (),
217 ),
218 (
219 'SkAutoTUnref',
220 (
221 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22222 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31223 ),
224 True,
225 (),
226 ),
227 (
228 'SkAutoUnref',
229 (
230 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
231 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22232 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31233 ),
234 True,
235 (),
236 ),
[email protected]d89eec82013-12-03 14:10:59237 (
238 r'/HANDLE_EINTR\(.*close',
239 (
240 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
241 'descriptor will be closed, and it is incorrect to retry the close.',
242 'Either call close directly and ignore its return value, or wrap close',
243 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
244 ),
245 True,
246 (),
247 ),
248 (
249 r'/IGNORE_EINTR\((?!.*close)',
250 (
251 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
252 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
253 ),
254 True,
255 (
256 # Files that #define IGNORE_EINTR.
257 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
258 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
259 ),
260 ),
[email protected]ec5b3f02014-04-04 18:43:43261 (
262 r'/v8::Extension\(',
263 (
264 'Do not introduce new v8::Extensions into the code base, use',
265 'gin::Wrappable instead. See http://crbug.com/334679',
266 ),
267 True,
[email protected]f55c90ee62014-04-12 00:50:03268 (
joaodasilva718f87672014-08-30 09:25:49269 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03270 ),
[email protected]ec5b3f02014-04-04 18:43:43271 ),
skyostilf9469f72015-04-20 10:38:52272 (
sdefresneeaeccc52015-04-22 08:18:32273 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52274 (
275 'MessageLoopProxy is deprecated. ',
276 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
277 ),
278 True,
kinuko59024ce2015-04-21 22:18:30279 (
280 # Internal message_loop related code may still use it.
281 r'^base[\\\/]message_loop[\\\/].*',
282 ),
skyostilf9469f72015-04-20 10:38:52283 ),
jame2d1a952016-04-02 00:27:10284 (
285 '#pragma comment(lib,',
286 (
287 'Specify libraries to link with in build files and not in the source.',
288 ),
289 True,
290 (),
291 ),
[email protected]127f18ec2012-06-16 05:05:59292)
293
mlamouria82272622014-09-16 18:45:04294_IPC_ENUM_TRAITS_DEPRECATED = (
295 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
296 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
297
[email protected]127f18ec2012-06-16 05:05:59298
[email protected]b00342e7f2013-03-26 16:21:54299_VALID_OS_MACROS = (
300 # Please keep sorted.
301 'OS_ANDROID',
302 'OS_BSD',
303 'OS_CAT', # For testing.
304 'OS_CHROMEOS',
305 'OS_FREEBSD',
306 'OS_IOS',
307 'OS_LINUX',
308 'OS_MACOSX',
309 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21310 'OS_NACL_NONSFI',
311 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54312 'OS_OPENBSD',
313 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37314 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54315 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54316 'OS_WIN',
317)
318
319
agrievef32bcc72016-04-04 14:57:40320_ANDROID_SPECIFIC_PYDEPS_FILES = [
321 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19322 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40323]
324
325_GENERIC_PYDEPS_FILES = [
326 'build/secondary/tools/swarming_client/isolate.pydeps',
327]
328
329_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
330
331
[email protected]55459852011-08-10 15:17:19332def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
333 """Attempts to prevent use of functions intended only for testing in
334 non-testing code. For now this is just a best-effort implementation
335 that ignores header files and may have some false positives. A
336 better implementation would probably need a proper C++ parser.
337 """
338 # We only scan .cc files and the like, as the declaration of
339 # for-testing functions in header files are hard to distinguish from
340 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44341 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19342
jochenc0d4808c2015-07-27 09:25:42343 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19344 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09345 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19346 exclusion_pattern = input_api.re.compile(
347 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
348 base_function_pattern, base_function_pattern))
349
350 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44351 black_list = (_EXCLUDED_PATHS +
352 _TEST_CODE_EXCLUDED_PATHS +
353 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19354 return input_api.FilterSourceFile(
355 affected_file,
356 white_list=(file_inclusion_pattern, ),
357 black_list=black_list)
358
359 problems = []
360 for f in input_api.AffectedSourceFiles(FilterFile):
361 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24362 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03363 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46364 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03365 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19366 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03367 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19368
369 if problems:
[email protected]f7051d52013-04-02 18:31:42370 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03371 else:
372 return []
[email protected]55459852011-08-10 15:17:19373
374
[email protected]10689ca2011-09-02 02:31:54375def _CheckNoIOStreamInHeaders(input_api, output_api):
376 """Checks to make sure no .h files include <iostream>."""
377 files = []
378 pattern = input_api.re.compile(r'^#include\s*<iostream>',
379 input_api.re.MULTILINE)
380 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
381 if not f.LocalPath().endswith('.h'):
382 continue
383 contents = input_api.ReadFile(f)
384 if pattern.search(contents):
385 files.append(f)
386
387 if len(files):
yolandyandaabc6d2016-04-18 18:29:39388 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06389 'Do not #include <iostream> in header files, since it inserts static '
390 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54391 '#include <ostream>. See http://crbug.com/94794',
392 files) ]
393 return []
394
395
[email protected]72df4e782012-06-21 16:28:18396def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52397 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18398 problems = []
399 for f in input_api.AffectedFiles():
400 if (not f.LocalPath().endswith(('.cc', '.mm'))):
401 continue
402
403 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04404 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18405 problems.append(' %s:%d' % (f.LocalPath(), line_num))
406
407 if not problems:
408 return []
409 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
410 '\n'.join(problems))]
411
412
danakj61c1aa22015-10-26 19:55:52413def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
414 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
415 errors = []
416 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
417 input_api.re.MULTILINE)
418 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
419 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
420 continue
421 for lnum, line in f.ChangedContents():
422 if input_api.re.search(pattern, line):
423 errors.append(output_api.PresubmitError(
424 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
425 'DCHECK_IS_ON()", not forgetting the braces.')
426 % (f.LocalPath(), lnum)))
427 return errors
428
429
mcasasb7440c282015-02-04 14:52:19430def _FindHistogramNameInLine(histogram_name, line):
431 """Tries to find a histogram name or prefix in a line."""
432 if not "affected-histogram" in line:
433 return histogram_name in line
434 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
435 # the histogram_name.
436 if not '"' in line:
437 return False
438 histogram_prefix = line.split('\"')[1]
439 return histogram_prefix in histogram_name
440
441
442def _CheckUmaHistogramChanges(input_api, output_api):
443 """Check that UMA histogram names in touched lines can still be found in other
444 lines of the patch or in histograms.xml. Note that this check would not catch
445 the reverse: changes in histograms.xml not matched in the code itself."""
446 touched_histograms = []
447 histograms_xml_modifications = []
448 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
449 for f in input_api.AffectedFiles():
450 # If histograms.xml itself is modified, keep the modified lines for later.
451 if f.LocalPath().endswith(('histograms.xml')):
452 histograms_xml_modifications = f.ChangedContents()
453 continue
454 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
455 continue
456 for line_num, line in f.ChangedContents():
457 found = pattern.search(line)
458 if found:
459 touched_histograms.append([found.group(1), f, line_num])
460
461 # Search for the touched histogram names in the local modifications to
462 # histograms.xml, and, if not found, on the base histograms.xml file.
463 unmatched_histograms = []
464 for histogram_info in touched_histograms:
465 histogram_name_found = False
466 for line_num, line in histograms_xml_modifications:
467 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
468 if histogram_name_found:
469 break
470 if not histogram_name_found:
471 unmatched_histograms.append(histogram_info)
472
eromanb90c82e7e32015-04-01 15:13:49473 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19474 problems = []
475 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49476 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19477 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45478 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19479 histogram_name_found = False
480 for line in histograms_xml:
481 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
482 if histogram_name_found:
483 break
484 if not histogram_name_found:
485 problems.append(' [%s:%d] %s' %
486 (f.LocalPath(), line_num, histogram_name))
487
488 if not problems:
489 return []
490 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
491 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49492 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19493
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
[email protected]8ea5d4b2011-09-13 21:49:22509def _CheckNoNewWStrings(input_api, output_api):
510 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27511 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22512 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20513 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57514 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
515 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20516 continue
[email protected]8ea5d4b2011-09-13 21:49:22517
[email protected]a11dbe9b2012-08-07 01:32:58518 allowWString = False
[email protected]b5c24292011-11-28 14:38:20519 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58520 if 'presubmit: allow wstring' in line:
521 allowWString = True
522 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27523 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58524 allowWString = False
525 else:
526 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22527
[email protected]55463aa62011-10-12 00:48:27528 if not problems:
529 return []
530 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58531 ' If you are calling a cross-platform API that accepts a wstring, '
532 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27533 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22534
535
[email protected]2a8ac9c2011-10-19 17:20:44536def _CheckNoDEPSGIT(input_api, output_api):
537 """Make sure .DEPS.git is never modified manually."""
538 if any(f.LocalPath().endswith('.DEPS.git') for f in
539 input_api.AffectedFiles()):
540 return [output_api.PresubmitError(
541 'Never commit changes to .DEPS.git. This file is maintained by an\n'
542 'automated system based on what\'s in DEPS and your changes will be\n'
543 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34544 '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:44545 'for more information')]
546 return []
547
548
tandriief664692014-09-23 14:51:47549def _CheckValidHostsInDEPS(input_api, output_api):
550 """Checks that DEPS file deps are from allowed_hosts."""
551 # Run only if DEPS file has been modified to annoy fewer bystanders.
552 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
553 return []
554 # Outsource work to gclient verify
555 try:
556 input_api.subprocess.check_output(['gclient', 'verify'])
557 return []
558 except input_api.subprocess.CalledProcessError, error:
559 return [output_api.PresubmitError(
560 'DEPS file must have only git dependencies.',
561 long_text=error.output)]
562
563
[email protected]127f18ec2012-06-16 05:05:59564def _CheckNoBannedFunctions(input_api, output_api):
565 """Make sure that banned functions are not used."""
566 warnings = []
567 errors = []
568
569 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
570 for f in input_api.AffectedFiles(file_filter=file_filter):
571 for line_num, line in f.ChangedContents():
572 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26573 matched = False
574 if func_name[0:1] == '/':
575 regex = func_name[1:]
576 if input_api.re.search(regex, line):
577 matched = True
578 elif func_name in line:
579 matched = True
580 if matched:
[email protected]127f18ec2012-06-16 05:05:59581 problems = warnings;
582 if error:
583 problems = errors;
584 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
585 for message_line in message:
586 problems.append(' %s' % message_line)
587
588 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
589 for f in input_api.AffectedFiles(file_filter=file_filter):
590 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49591 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
592 def IsBlacklisted(affected_file, blacklist):
593 local_path = affected_file.LocalPath()
594 for item in blacklist:
595 if input_api.re.match(item, local_path):
596 return True
597 return False
598 if IsBlacklisted(f, excluded_paths):
599 continue
[email protected]d89eec82013-12-03 14:10:59600 matched = False
601 if func_name[0:1] == '/':
602 regex = func_name[1:]
603 if input_api.re.search(regex, line):
604 matched = True
605 elif func_name in line:
606 matched = True
607 if matched:
[email protected]127f18ec2012-06-16 05:05:59608 problems = warnings;
609 if error:
610 problems = errors;
611 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
612 for message_line in message:
613 problems.append(' %s' % message_line)
614
615 result = []
616 if (warnings):
617 result.append(output_api.PresubmitPromptWarning(
618 'Banned functions were used.\n' + '\n'.join(warnings)))
619 if (errors):
620 result.append(output_api.PresubmitError(
621 'Banned functions were used.\n' + '\n'.join(errors)))
622 return result
623
624
[email protected]6c063c62012-07-11 19:11:06625def _CheckNoPragmaOnce(input_api, output_api):
626 """Make sure that banned functions are not used."""
627 files = []
628 pattern = input_api.re.compile(r'^#pragma\s+once',
629 input_api.re.MULTILINE)
630 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
631 if not f.LocalPath().endswith('.h'):
632 continue
633 contents = input_api.ReadFile(f)
634 if pattern.search(contents):
635 files.append(f)
636
637 if files:
638 return [output_api.PresubmitError(
639 'Do not use #pragma once in header files.\n'
640 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
641 files)]
642 return []
643
[email protected]127f18ec2012-06-16 05:05:59644
[email protected]e7479052012-09-19 00:26:12645def _CheckNoTrinaryTrueFalse(input_api, output_api):
646 """Checks to make sure we don't introduce use of foo ? true : false."""
647 problems = []
648 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
649 for f in input_api.AffectedFiles():
650 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
651 continue
652
653 for line_num, line in f.ChangedContents():
654 if pattern.match(line):
655 problems.append(' %s:%d' % (f.LocalPath(), line_num))
656
657 if not problems:
658 return []
659 return [output_api.PresubmitPromptWarning(
660 'Please consider avoiding the "? true : false" pattern if possible.\n' +
661 '\n'.join(problems))]
662
663
[email protected]55f9f382012-07-31 11:02:18664def _CheckUnwantedDependencies(input_api, output_api):
665 """Runs checkdeps on #include statements added in this
666 change. Breaking - rules is an error, breaking ! rules is a
667 warning.
668 """
mohan.reddyf21db962014-10-16 12:26:47669 import sys
[email protected]55f9f382012-07-31 11:02:18670 # We need to wait until we have an input_api object and use this
671 # roundabout construct to import checkdeps because this file is
672 # eval-ed and thus doesn't have __file__.
673 original_sys_path = sys.path
674 try:
675 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47676 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18677 import checkdeps
678 from cpp_checker import CppChecker
679 from rules import Rule
680 finally:
681 # Restore sys.path to what it was before.
682 sys.path = original_sys_path
683
684 added_includes = []
685 for f in input_api.AffectedFiles():
686 if not CppChecker.IsCppFile(f.LocalPath()):
687 continue
688
689 changed_lines = [line for line_num, line in f.ChangedContents()]
690 added_includes.append([f.LocalPath(), changed_lines])
691
[email protected]26385172013-05-09 23:11:35692 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18693
694 error_descriptions = []
695 warning_descriptions = []
696 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
697 added_includes):
698 description_with_path = '%s\n %s' % (path, rule_description)
699 if rule_type == Rule.DISALLOW:
700 error_descriptions.append(description_with_path)
701 else:
702 warning_descriptions.append(description_with_path)
703
704 results = []
705 if error_descriptions:
706 results.append(output_api.PresubmitError(
707 'You added one or more #includes that violate checkdeps rules.',
708 error_descriptions))
709 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42710 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18711 'You added one or more #includes of files that are temporarily\n'
712 'allowed but being removed. Can you avoid introducing the\n'
713 '#include? See relevant DEPS file(s) for details and contacts.',
714 warning_descriptions))
715 return results
716
717
[email protected]fbcafe5a2012-08-08 15:31:22718def _CheckFilePermissions(input_api, output_api):
719 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15720 if input_api.platform == 'win32':
721 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29722 checkperms_tool = input_api.os_path.join(
723 input_api.PresubmitLocalPath(),
724 'tools', 'checkperms', 'checkperms.py')
725 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47726 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22727 for f in input_api.AffectedFiles():
728 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11729 try:
730 input_api.subprocess.check_output(args)
731 return []
732 except input_api.subprocess.CalledProcessError as error:
733 return [output_api.PresubmitError(
734 'checkperms.py failed:',
735 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22736
737
[email protected]c8278b32012-10-30 20:35:49738def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
739 """Makes sure we don't include ui/aura/window_property.h
740 in header files.
741 """
742 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
743 errors = []
744 for f in input_api.AffectedFiles():
745 if not f.LocalPath().endswith('.h'):
746 continue
747 for line_num, line in f.ChangedContents():
748 if pattern.match(line):
749 errors.append(' %s:%d' % (f.LocalPath(), line_num))
750
751 results = []
752 if errors:
753 results.append(output_api.PresubmitError(
754 'Header files should not include ui/aura/window_property.h', errors))
755 return results
756
757
[email protected]cf9b78f2012-11-14 11:40:28758def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
759 """Checks that the lines in scope occur in the right order.
760
761 1. C system files in alphabetical order
762 2. C++ system files in alphabetical order
763 3. Project's .h files
764 """
765
766 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
767 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
768 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
769
770 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
771
772 state = C_SYSTEM_INCLUDES
773
774 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57775 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28776 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55777 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28778 for line_num, line in scope:
779 if c_system_include_pattern.match(line):
780 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55781 problem_linenums.append((line_num, previous_line_num,
782 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28783 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55784 problem_linenums.append((line_num, previous_line_num,
785 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28786 elif cpp_system_include_pattern.match(line):
787 if state == C_SYSTEM_INCLUDES:
788 state = CPP_SYSTEM_INCLUDES
789 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55790 problem_linenums.append((line_num, previous_line_num,
791 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28792 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55793 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28794 elif custom_include_pattern.match(line):
795 if state != CUSTOM_INCLUDES:
796 state = CUSTOM_INCLUDES
797 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55798 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28799 else:
brucedawson70fadb02015-06-30 17:47:55800 problem_linenums.append((line_num, previous_line_num,
801 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28802 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57803 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28804
805 warnings = []
brucedawson70fadb02015-06-30 17:47:55806 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57807 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55808 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28809 return warnings
810
811
[email protected]ac294a12012-12-06 16:38:43812def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28813 """Checks the #include order for the given file f."""
814
[email protected]2299dcf2012-11-15 19:56:24815 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30816 # Exclude the following includes from the check:
817 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
818 # specific order.
819 # 2) <atlbase.h>, "build/build_config.h"
820 excluded_include_pattern = input_api.re.compile(
821 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24822 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33823 # Match the final or penultimate token if it is xxxtest so we can ignore it
824 # when considering the special first include.
825 test_file_tag_pattern = input_api.re.compile(
826 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11827 if_pattern = input_api.re.compile(
828 r'\s*#\s*(if|elif|else|endif|define|undef).*')
829 # Some files need specialized order of includes; exclude such files from this
830 # check.
831 uncheckable_includes_pattern = input_api.re.compile(
832 r'\s*#include '
833 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28834
835 contents = f.NewContents()
836 warnings = []
837 line_num = 0
838
[email protected]ac294a12012-12-06 16:38:43839 # Handle the special first include. If the first include file is
840 # some/path/file.h, the corresponding including file can be some/path/file.cc,
841 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
842 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33843 # If the included file is some/path/file_platform.h the including file could
844 # also be some/path/file_xxxtest_platform.h.
845 including_file_base_name = test_file_tag_pattern.sub(
846 '', input_api.os_path.basename(f.LocalPath()))
847
[email protected]ac294a12012-12-06 16:38:43848 for line in contents:
849 line_num += 1
850 if system_include_pattern.match(line):
851 # No special first include -> process the line again along with normal
852 # includes.
853 line_num -= 1
854 break
855 match = custom_include_pattern.match(line)
856 if match:
857 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33858 header_basename = test_file_tag_pattern.sub(
859 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
860
861 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24862 # No special first include -> process the line again along with normal
863 # includes.
864 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43865 break
[email protected]cf9b78f2012-11-14 11:40:28866
867 # Split into scopes: Each region between #if and #endif is its own scope.
868 scopes = []
869 current_scope = []
870 for line in contents[line_num:]:
871 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11872 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54873 continue
[email protected]2309b0fa02012-11-16 12:18:27874 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28875 scopes.append(current_scope)
876 current_scope = []
[email protected]962f117e2012-11-22 18:11:56877 elif ((system_include_pattern.match(line) or
878 custom_include_pattern.match(line)) and
879 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28880 current_scope.append((line_num, line))
881 scopes.append(current_scope)
882
883 for scope in scopes:
884 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
885 changed_linenums))
886 return warnings
887
888
889def _CheckIncludeOrder(input_api, output_api):
890 """Checks that the #include order is correct.
891
892 1. The corresponding header for source files.
893 2. C system files in alphabetical order
894 3. C++ system files in alphabetical order
895 4. Project's .h files in alphabetical order
896
[email protected]ac294a12012-12-06 16:38:43897 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
898 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28899 """
[email protected]e120b012014-08-15 19:08:35900 def FileFilterIncludeOrder(affected_file):
901 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
902 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28903
904 warnings = []
[email protected]e120b012014-08-15 19:08:35905 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08906 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43907 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
908 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28909
910 results = []
911 if warnings:
[email protected]f7051d52013-04-02 18:31:42912 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53913 warnings))
[email protected]cf9b78f2012-11-14 11:40:28914 return results
915
916
[email protected]70ca77752012-11-20 03:45:03917def _CheckForVersionControlConflictsInFile(input_api, f):
918 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
919 errors = []
920 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23921 if f.LocalPath().endswith('.md'):
922 # First-level headers in markdown look a lot like version control
923 # conflict markers. http://daringfireball.net/projects/markdown/basics
924 continue
[email protected]70ca77752012-11-20 03:45:03925 if pattern.match(line):
926 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
927 return errors
928
929
930def _CheckForVersionControlConflicts(input_api, output_api):
931 """Usually this is not intentional and will cause a compile failure."""
932 errors = []
933 for f in input_api.AffectedFiles():
934 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
935
936 results = []
937 if errors:
938 results.append(output_api.PresubmitError(
939 'Version control conflict markers found, please resolve.', errors))
940 return results
941
942
[email protected]06e6d0ff2012-12-11 01:36:44943def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
944 def FilterFile(affected_file):
945 """Filter function for use with input_api.AffectedSourceFiles,
946 below. This filters out everything except non-test files from
947 top-level directories that generally speaking should not hard-code
948 service URLs (e.g. src/android_webview/, src/content/ and others).
949 """
950 return input_api.FilterSourceFile(
951 affected_file,
[email protected]78bb39d62012-12-11 15:11:56952 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44953 black_list=(_EXCLUDED_PATHS +
954 _TEST_CODE_EXCLUDED_PATHS +
955 input_api.DEFAULT_BLACK_LIST))
956
reillyi38965732015-11-16 18:27:33957 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
958 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46959 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
960 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44961 problems = [] # items are (filename, line_number, line)
962 for f in input_api.AffectedSourceFiles(FilterFile):
963 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46964 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44965 problems.append((f.LocalPath(), line_num, line))
966
967 if problems:
[email protected]f7051d52013-04-02 18:31:42968 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44969 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58970 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44971 [' %s:%d: %s' % (
972 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03973 else:
974 return []
[email protected]06e6d0ff2012-12-11 01:36:44975
976
[email protected]d2530012013-01-25 16:39:27977def _CheckNoAbbreviationInPngFileName(input_api, output_api):
978 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31979 The native_client_sdk directory is excluded because it has auto-generated PNG
980 files for documentation.
[email protected]d2530012013-01-25 16:39:27981 """
[email protected]d2530012013-01-25 16:39:27982 errors = []
binji0dcdf342014-12-12 18:32:31983 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
984 black_list = (r'^native_client_sdk[\\\/]',)
985 file_filter = lambda f: input_api.FilterSourceFile(
986 f, white_list=white_list, black_list=black_list)
987 for f in input_api.AffectedFiles(include_deletes=False,
988 file_filter=file_filter):
989 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27990
991 results = []
992 if errors:
993 results.append(output_api.PresubmitError(
994 'The name of PNG files should not have abbreviations. \n'
995 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
996 'Contact [email protected] if you have questions.', errors))
997 return results
998
999
[email protected]14a6131c2014-01-08 01:15:411000def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:081001 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411002 a set of DEPS entries that we should look up.
1003
1004 For a directory (rather than a specific filename) we fake a path to
1005 a specific filename by adding /DEPS. This is chosen as a file that
1006 will seldom or never be subject to per-file include_rules.
1007 """
[email protected]2b438d62013-11-14 17:54:141008 # We ignore deps entries on auto-generated directories.
1009 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081010
1011 # This pattern grabs the path without basename in the first
1012 # parentheses, and the basename (if present) in the second. It
1013 # relies on the simple heuristic that if there is a basename it will
1014 # be a header file ending in ".h".
1015 pattern = re.compile(
1016 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141017 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081018 for changed_line in changed_lines:
1019 m = pattern.match(changed_line)
1020 if m:
1021 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141022 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411023 if m.group(2):
1024 results.add('%s%s' % (path, m.group(2)))
1025 else:
1026 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081027 return results
1028
1029
[email protected]e871964c2013-05-13 14:14:551030def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1031 """When a dependency prefixed with + is added to a DEPS file, we
1032 want to make sure that the change is reviewed by an OWNER of the
1033 target file or directory, to avoid layering violations from being
1034 introduced. This check verifies that this happens.
1035 """
1036 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241037
1038 file_filter = lambda f: not input_api.re.match(
1039 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1040 for f in input_api.AffectedFiles(include_deletes=False,
1041 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551042 filename = input_api.os_path.basename(f.LocalPath())
1043 if filename == 'DEPS':
1044 changed_lines |= set(line.strip()
1045 for line_num, line
1046 in f.ChangedContents())
1047 if not changed_lines:
1048 return []
1049
[email protected]14a6131c2014-01-08 01:15:411050 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1051 changed_lines)
[email protected]e871964c2013-05-13 14:14:551052 if not virtual_depended_on_files:
1053 return []
1054
1055 if input_api.is_committing:
1056 if input_api.tbr:
1057 return [output_api.PresubmitNotifyResult(
1058 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271059 if input_api.dry_run:
1060 return [output_api.PresubmitNotifyResult(
1061 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551062 if not input_api.change.issue:
1063 return [output_api.PresubmitError(
1064 "DEPS approval by OWNERS check failed: this change has "
1065 "no Rietveld issue number, so we can't check it for approvals.")]
1066 output = output_api.PresubmitError
1067 else:
1068 output = output_api.PresubmitNotifyResult
1069
1070 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501071 owner_email, reviewers = (
1072 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1073 input_api,
1074 owners_db.email_regexp,
1075 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551076
1077 owner_email = owner_email or input_api.change.author_email
1078
[email protected]de4f7d22013-05-23 14:27:461079 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511080 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461081 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551082 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1083 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411084
1085 # We strip the /DEPS part that was added by
1086 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1087 # directory.
1088 def StripDeps(path):
1089 start_deps = path.rfind('/DEPS')
1090 if start_deps != -1:
1091 return path[:start_deps]
1092 else:
1093 return path
1094 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551095 for path in missing_files]
1096
1097 if unapproved_dependencies:
1098 output_list = [
[email protected]14a6131c2014-01-08 01:15:411099 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551100 '\n '.join(sorted(unapproved_dependencies)))]
1101 if not input_api.is_committing:
1102 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1103 output_list.append(output(
1104 'Suggested missing target path OWNERS:\n %s' %
1105 '\n '.join(suggested_owners or [])))
1106 return output_list
1107
1108 return []
1109
1110
[email protected]85218562013-11-22 07:41:401111def _CheckSpamLogging(input_api, output_api):
1112 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1113 black_list = (_EXCLUDED_PATHS +
1114 _TEST_CODE_EXCLUDED_PATHS +
1115 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501116 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191117 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481118 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461119 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121120 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1121 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581122 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161123 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031124 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151125 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1126 r"^chromecast[\\\/]",
1127 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311128 r"^components[\\\/]html_viewer[\\\/]"
1129 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461130 # TODO(peter): Remove this exception. https://crbug.com/534537
1131 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1132 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251133 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1134 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111135 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151136 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111137 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521138 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501139 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361140 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311141 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131142 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441143 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451144 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021145 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441146 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401147 source_file_filter = lambda x: input_api.FilterSourceFile(
1148 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1149
1150 log_info = []
1151 printf = []
1152
1153 for f in input_api.AffectedSourceFiles(source_file_filter):
1154 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471155 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401156 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471157 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131158 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371159
mohan.reddyf21db962014-10-16 12:26:471160 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371161 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471162 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401163 printf.append(f.LocalPath())
1164
1165 if log_info:
1166 return [output_api.PresubmitError(
1167 'These files spam the console log with LOG(INFO):',
1168 items=log_info)]
1169 if printf:
1170 return [output_api.PresubmitError(
1171 'These files spam the console log with printf/fprintf:',
1172 items=printf)]
1173 return []
1174
1175
[email protected]49aa76a2013-12-04 06:59:161176def _CheckForAnonymousVariables(input_api, output_api):
1177 """These types are all expected to hold locks while in scope and
1178 so should never be anonymous (which causes them to be immediately
1179 destroyed)."""
1180 they_who_must_be_named = [
1181 'base::AutoLock',
1182 'base::AutoReset',
1183 'base::AutoUnlock',
1184 'SkAutoAlphaRestore',
1185 'SkAutoBitmapShaderInstall',
1186 'SkAutoBlitterChoose',
1187 'SkAutoBounderCommit',
1188 'SkAutoCallProc',
1189 'SkAutoCanvasRestore',
1190 'SkAutoCommentBlock',
1191 'SkAutoDescriptor',
1192 'SkAutoDisableDirectionCheck',
1193 'SkAutoDisableOvalCheck',
1194 'SkAutoFree',
1195 'SkAutoGlyphCache',
1196 'SkAutoHDC',
1197 'SkAutoLockColors',
1198 'SkAutoLockPixels',
1199 'SkAutoMalloc',
1200 'SkAutoMaskFreeImage',
1201 'SkAutoMutexAcquire',
1202 'SkAutoPathBoundsUpdate',
1203 'SkAutoPDFRelease',
1204 'SkAutoRasterClipValidate',
1205 'SkAutoRef',
1206 'SkAutoTime',
1207 'SkAutoTrace',
1208 'SkAutoUnref',
1209 ]
1210 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1211 # bad: base::AutoLock(lock.get());
1212 # not bad: base::AutoLock lock(lock.get());
1213 bad_pattern = input_api.re.compile(anonymous)
1214 # good: new base::AutoLock(lock.get())
1215 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1216 errors = []
1217
1218 for f in input_api.AffectedFiles():
1219 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1220 continue
1221 for linenum, line in f.ChangedContents():
1222 if bad_pattern.search(line) and not good_pattern.search(line):
1223 errors.append('%s:%d' % (f.LocalPath(), linenum))
1224
1225 if errors:
1226 return [output_api.PresubmitError(
1227 'These lines create anonymous variables that need to be named:',
1228 items=errors)]
1229 return []
1230
1231
[email protected]5fe0f8742013-11-29 01:04:591232def _CheckCygwinShell(input_api, output_api):
1233 source_file_filter = lambda x: input_api.FilterSourceFile(
1234 x, white_list=(r'.+\.(gyp|gypi)$',))
1235 cygwin_shell = []
1236
1237 for f in input_api.AffectedSourceFiles(source_file_filter):
1238 for linenum, line in f.ChangedContents():
1239 if 'msvs_cygwin_shell' in line:
1240 cygwin_shell.append(f.LocalPath())
1241 break
1242
1243 if cygwin_shell:
1244 return [output_api.PresubmitError(
1245 'These files should not use msvs_cygwin_shell (the default is 0):',
1246 items=cygwin_shell)]
1247 return []
1248
[email protected]85218562013-11-22 07:41:401249
[email protected]999261d2014-03-03 20:08:081250def _CheckUserActionUpdate(input_api, output_api):
1251 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521252 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081253 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521254 # If actions.xml is already included in the changelist, the PRESUBMIT
1255 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081256 return []
1257
[email protected]999261d2014-03-03 20:08:081258 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1259 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521260 current_actions = None
[email protected]999261d2014-03-03 20:08:081261 for f in input_api.AffectedFiles(file_filter=file_filter):
1262 for line_num, line in f.ChangedContents():
1263 match = input_api.re.search(action_re, line)
1264 if match:
[email protected]2f92dec2014-03-07 19:21:521265 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1266 # loaded only once.
1267 if not current_actions:
1268 with open('tools/metrics/actions/actions.xml') as actions_f:
1269 current_actions = actions_f.read()
1270 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081271 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521272 action = 'name="{0}"'.format(action_name)
1273 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081274 return [output_api.PresubmitPromptWarning(
1275 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521276 'tools/metrics/actions/actions.xml. Please run '
1277 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081278 % (f.LocalPath(), line_num, action_name))]
1279 return []
1280
1281
[email protected]99171a92014-06-03 08:44:471282def _GetJSONParseError(input_api, filename, eat_comments=True):
1283 try:
1284 contents = input_api.ReadFile(filename)
1285 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131286 import sys
1287 original_sys_path = sys.path
1288 try:
1289 sys.path = sys.path + [input_api.os_path.join(
1290 input_api.PresubmitLocalPath(),
1291 'tools', 'json_comment_eater')]
1292 import json_comment_eater
1293 finally:
1294 sys.path = original_sys_path
1295 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471296
1297 input_api.json.loads(contents)
1298 except ValueError as e:
1299 return e
1300 return None
1301
1302
1303def _GetIDLParseError(input_api, filename):
1304 try:
1305 contents = input_api.ReadFile(filename)
1306 idl_schema = input_api.os_path.join(
1307 input_api.PresubmitLocalPath(),
1308 'tools', 'json_schema_compiler', 'idl_schema.py')
1309 process = input_api.subprocess.Popen(
1310 [input_api.python_executable, idl_schema],
1311 stdin=input_api.subprocess.PIPE,
1312 stdout=input_api.subprocess.PIPE,
1313 stderr=input_api.subprocess.PIPE,
1314 universal_newlines=True)
1315 (_, error) = process.communicate(input=contents)
1316 return error or None
1317 except ValueError as e:
1318 return e
1319
1320
1321def _CheckParseErrors(input_api, output_api):
1322 """Check that IDL and JSON files do not contain syntax errors."""
1323 actions = {
1324 '.idl': _GetIDLParseError,
1325 '.json': _GetJSONParseError,
1326 }
1327 # These paths contain test data and other known invalid JSON files.
1328 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491329 r'test[\\\/]data[\\\/]',
1330 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471331 ]
1332 # Most JSON files are preprocessed and support comments, but these do not.
1333 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491334 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471335 ]
1336 # Only run IDL checker on files in these directories.
1337 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491338 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1339 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471340 ]
1341
1342 def get_action(affected_file):
1343 filename = affected_file.LocalPath()
1344 return actions.get(input_api.os_path.splitext(filename)[1])
1345
1346 def MatchesFile(patterns, path):
1347 for pattern in patterns:
1348 if input_api.re.search(pattern, path):
1349 return True
1350 return False
1351
1352 def FilterFile(affected_file):
1353 action = get_action(affected_file)
1354 if not action:
1355 return False
1356 path = affected_file.LocalPath()
1357
1358 if MatchesFile(excluded_patterns, path):
1359 return False
1360
1361 if (action == _GetIDLParseError and
1362 not MatchesFile(idl_included_patterns, path)):
1363 return False
1364 return True
1365
1366 results = []
1367 for affected_file in input_api.AffectedFiles(
1368 file_filter=FilterFile, include_deletes=False):
1369 action = get_action(affected_file)
1370 kwargs = {}
1371 if (action == _GetJSONParseError and
1372 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1373 kwargs['eat_comments'] = False
1374 parse_error = action(input_api,
1375 affected_file.AbsoluteLocalPath(),
1376 **kwargs)
1377 if parse_error:
1378 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1379 (affected_file.LocalPath(), parse_error)))
1380 return results
1381
1382
[email protected]760deea2013-12-10 19:33:491383def _CheckJavaStyle(input_api, output_api):
1384 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471385 import sys
[email protected]760deea2013-12-10 19:33:491386 original_sys_path = sys.path
1387 try:
1388 sys.path = sys.path + [input_api.os_path.join(
1389 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1390 import checkstyle
1391 finally:
1392 # Restore sys.path to what it was before.
1393 sys.path = original_sys_path
1394
1395 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091396 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511397 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491398
1399
dskiba88634f4e2015-08-14 23:03:291400def _CheckAndroidToastUsage(input_api, output_api):
1401 """Checks that code uses org.chromium.ui.widget.Toast instead of
1402 android.widget.Toast (Chromium Toast doesn't force hardware
1403 acceleration on low-end devices, saving memory).
1404 """
1405 toast_import_pattern = input_api.re.compile(
1406 r'^import android\.widget\.Toast;$')
1407
1408 errors = []
1409
1410 sources = lambda affected_file: input_api.FilterSourceFile(
1411 affected_file,
1412 black_list=(_EXCLUDED_PATHS +
1413 _TEST_CODE_EXCLUDED_PATHS +
1414 input_api.DEFAULT_BLACK_LIST +
1415 (r'^chromecast[\\\/].*',
1416 r'^remoting[\\\/].*')),
1417 white_list=(r'.*\.java$',))
1418
1419 for f in input_api.AffectedSourceFiles(sources):
1420 for line_num, line in f.ChangedContents():
1421 if toast_import_pattern.search(line):
1422 errors.append("%s:%d" % (f.LocalPath(), line_num))
1423
1424 results = []
1425
1426 if errors:
1427 results.append(output_api.PresubmitError(
1428 'android.widget.Toast usage is detected. Android toasts use hardware'
1429 ' acceleration, and can be\ncostly on low-end devices. Please use'
1430 ' org.chromium.ui.widget.Toast instead.\n'
1431 'Contact [email protected] if you have any questions.',
1432 errors))
1433
1434 return results
1435
1436
dgnaa68d5e2015-06-10 10:08:221437def _CheckAndroidCrLogUsage(input_api, output_api):
1438 """Checks that new logs using org.chromium.base.Log:
1439 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511440 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221441 """
pkotwicza1dd0b002016-05-16 14:41:041442
1443 # Do not check format of logs in //chrome/android/webapk because
1444 # //chrome/android/webapk cannot depend on //base
1445 cr_log_check_excluded_paths = [
1446 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1447 ]
1448
dgnaa68d5e2015-06-10 10:08:221449 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121450 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1451 class_in_base_pattern = input_api.re.compile(
1452 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1453 has_some_log_import_pattern = input_api.re.compile(
1454 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221455 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121456 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221457 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511458 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221459 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221460
Vincent Scheib16d7b272015-09-15 18:09:071461 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221462 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041463 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1464 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121465
dgnaa68d5e2015-06-10 10:08:221466 tag_decl_errors = []
1467 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121468 tag_errors = []
dgn38736db2015-09-18 19:20:511469 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121470 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221471
1472 for f in input_api.AffectedSourceFiles(sources):
1473 file_content = input_api.ReadFile(f)
1474 has_modified_logs = False
1475
1476 # Per line checks
dgn87d9fb62015-06-12 09:15:121477 if (cr_log_import_pattern.search(file_content) or
1478 (class_in_base_pattern.search(file_content) and
1479 not has_some_log_import_pattern.search(file_content))):
1480 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221481 for line_num, line in f.ChangedContents():
1482
1483 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121484 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221485 if match:
1486 has_modified_logs = True
1487
1488 # Make sure it uses "TAG"
1489 if not match.group('tag') == 'TAG':
1490 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121491 else:
1492 # Report non cr Log function calls in changed lines
1493 for line_num, line in f.ChangedContents():
1494 if log_call_pattern.search(line):
1495 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221496
1497 # Per file checks
1498 if has_modified_logs:
1499 # Make sure the tag is using the "cr" prefix and is not too long
1500 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511501 tag_name = match.group('name') if match else None
1502 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221503 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511504 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221505 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511506 elif '.' in tag_name:
1507 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221508
1509 results = []
1510 if tag_decl_errors:
1511 results.append(output_api.PresubmitPromptWarning(
1512 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511513 '"private static final String TAG = "<package tag>".\n'
1514 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221515 tag_decl_errors))
1516
1517 if tag_length_errors:
1518 results.append(output_api.PresubmitError(
1519 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511520 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221521 tag_length_errors))
1522
1523 if tag_errors:
1524 results.append(output_api.PresubmitPromptWarning(
1525 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1526 tag_errors))
1527
dgn87d9fb62015-06-12 09:15:121528 if util_log_errors:
dgn4401aa52015-04-29 16:26:171529 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121530 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1531 util_log_errors))
1532
dgn38736db2015-09-18 19:20:511533 if tag_with_dot_errors:
1534 results.append(output_api.PresubmitPromptWarning(
1535 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1536 tag_with_dot_errors))
1537
dgn4401aa52015-04-29 16:26:171538 return results
1539
1540
agrieve7b6479d82015-10-07 14:24:221541def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1542 """Checks if MDPI assets are placed in a correct directory."""
1543 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1544 ('/res/drawable/' in f.LocalPath() or
1545 '/res/drawable-ldrtl/' in f.LocalPath()))
1546 errors = []
1547 for f in input_api.AffectedFiles(include_deletes=False,
1548 file_filter=file_filter):
1549 errors.append(' %s' % f.LocalPath())
1550
1551 results = []
1552 if errors:
1553 results.append(output_api.PresubmitError(
1554 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1555 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1556 '/res/drawable-ldrtl/.\n'
1557 'Contact [email protected] if you have questions.', errors))
1558 return results
1559
1560
agrievef32bcc72016-04-04 14:57:401561class PydepsChecker(object):
1562 def __init__(self, input_api, pydeps_files):
1563 self._file_cache = {}
1564 self._input_api = input_api
1565 self._pydeps_files = pydeps_files
1566
1567 def _LoadFile(self, path):
1568 """Returns the list of paths within a .pydeps file relative to //."""
1569 if path not in self._file_cache:
1570 with open(path) as f:
1571 self._file_cache[path] = f.read()
1572 return self._file_cache[path]
1573
1574 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1575 """Returns an interable of paths within the .pydep, relativized to //."""
1576 os_path = self._input_api.os_path
1577 pydeps_dir = os_path.dirname(pydeps_path)
1578 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1579 if not l.startswith('*'))
1580 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1581
1582 def _CreateFilesToPydepsMap(self):
1583 """Returns a map of local_path -> list_of_pydeps."""
1584 ret = {}
1585 for pydep_local_path in self._pydeps_files:
1586 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1587 ret.setdefault(path, []).append(pydep_local_path)
1588 return ret
1589
1590 def ComputeAffectedPydeps(self):
1591 """Returns an iterable of .pydeps files that might need regenerating."""
1592 affected_pydeps = set()
1593 file_to_pydeps_map = None
1594 for f in self._input_api.AffectedFiles(include_deletes=True):
1595 local_path = f.LocalPath()
1596 if local_path == 'DEPS':
1597 return self._pydeps_files
1598 elif local_path.endswith('.pydeps'):
1599 if local_path in self._pydeps_files:
1600 affected_pydeps.add(local_path)
1601 elif local_path.endswith('.py'):
1602 if file_to_pydeps_map is None:
1603 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1604 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1605 return affected_pydeps
1606
1607 def DetermineIfStale(self, pydeps_path):
1608 """Runs print_python_deps.py to see if the files is stale."""
1609 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1610 cmd = old_pydeps_data[1][1:].strip()
1611 new_pydeps_data = self._input_api.subprocess.check_output(
1612 cmd + ' --output ""', shell=True)
1613 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1614 return cmd
1615
1616
1617def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1618 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001619 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281620 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1621 # Mac, so skip it on other platforms.
1622 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001623 return []
agrievef32bcc72016-04-04 14:57:401624 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1625 is_android = input_api.os_path.exists('third_party/android_tools')
1626 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1627 results = []
1628 # First, check for new / deleted .pydeps.
1629 for f in input_api.AffectedFiles(include_deletes=True):
1630 if f.LocalPath().endswith('.pydeps'):
1631 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1632 results.append(output_api.PresubmitError(
1633 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1634 'remove %s' % f.LocalPath()))
1635 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1636 results.append(output_api.PresubmitError(
1637 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1638 'include %s' % f.LocalPath()))
1639
1640 if results:
1641 return results
1642
1643 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1644
1645 for pydep_path in checker.ComputeAffectedPydeps():
1646 try:
1647 cmd = checker.DetermineIfStale(pydep_path)
1648 if cmd:
1649 results.append(output_api.PresubmitError(
1650 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1651 (pydep_path, cmd)))
1652 except input_api.subprocess.CalledProcessError as error:
1653 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1654 long_text=error.output)]
1655
1656 return results
1657
1658
mnaganov9b9b1fe82014-12-11 16:30:361659def _CheckForCopyrightedCode(input_api, output_api):
1660 """Verifies that newly added code doesn't contain copyrighted material
1661 and is properly licensed under the standard Chromium license.
1662
1663 As there can be false positives, we maintain a whitelist file. This check
1664 also verifies that the whitelist file is up to date.
1665 """
1666 import sys
1667 original_sys_path = sys.path
1668 try:
1669 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221670 input_api.PresubmitLocalPath(), 'tools')]
1671 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361672 finally:
1673 # Restore sys.path to what it was before.
1674 sys.path = original_sys_path
1675
1676 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1677
1678
glidere61efad2015-02-18 17:39:431679def _CheckSingletonInHeaders(input_api, output_api):
1680 """Checks to make sure no header files have |Singleton<|."""
1681 def FileFilter(affected_file):
1682 # It's ok for base/memory/singleton.h to have |Singleton<|.
1683 black_list = (_EXCLUDED_PATHS +
1684 input_api.DEFAULT_BLACK_LIST +
1685 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1686 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1687
sergeyu34d21222015-09-16 00:11:441688 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431689 files = []
1690 for f in input_api.AffectedSourceFiles(FileFilter):
1691 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1692 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1693 contents = input_api.ReadFile(f)
1694 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241695 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431696 pattern.search(line)):
1697 files.append(f)
1698 break
1699
1700 if files:
yolandyandaabc6d2016-04-18 18:29:391701 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441702 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431703 'Please move them to an appropriate source file so that the ' +
1704 'template gets instantiated in a single compilation unit.',
1705 files) ]
1706 return []
1707
1708
dbeam37e8e7402016-02-10 22:58:201709def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1710 """Checks for old style compiled_resources.gyp files."""
1711 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1712
1713 added_compiled_resources = filter(is_compiled_resource, [
1714 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1715 ])
1716
1717 if not added_compiled_resources:
1718 return []
1719
1720 return [output_api.PresubmitError(
1721 "Found new compiled_resources.gyp files:\n%s\n\n"
1722 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551723 "please use compiled_resources2.gyp instead:\n"
1724 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1725 %
dbeam37e8e7402016-02-10 22:58:201726 "\n".join(added_compiled_resources))]
1727
1728
[email protected]fd20b902014-05-09 02:14:531729_DEPRECATED_CSS = [
1730 # Values
1731 ( "-webkit-box", "flex" ),
1732 ( "-webkit-inline-box", "inline-flex" ),
1733 ( "-webkit-flex", "flex" ),
1734 ( "-webkit-inline-flex", "inline-flex" ),
1735 ( "-webkit-min-content", "min-content" ),
1736 ( "-webkit-max-content", "max-content" ),
1737
1738 # Properties
1739 ( "-webkit-background-clip", "background-clip" ),
1740 ( "-webkit-background-origin", "background-origin" ),
1741 ( "-webkit-background-size", "background-size" ),
1742 ( "-webkit-box-shadow", "box-shadow" ),
1743
1744 # Functions
1745 ( "-webkit-gradient", "gradient" ),
1746 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1747 ( "-webkit-linear-gradient", "linear-gradient" ),
1748 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1749 ( "-webkit-radial-gradient", "radial-gradient" ),
1750 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1751]
1752
1753def _CheckNoDeprecatedCSS(input_api, output_api):
1754 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251755 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341756 documentation and iOS CSS for dom distiller
1757 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251758 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531759 results = []
dbeam070cfe62014-10-22 06:44:021760 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251761 black_list = (_EXCLUDED_PATHS +
1762 _TEST_CODE_EXCLUDED_PATHS +
1763 input_api.DEFAULT_BLACK_LIST +
1764 (r"^chrome/common/extensions/docs",
1765 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341766 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051767 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441768 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251769 r"^native_client_sdk"))
1770 file_filter = lambda f: input_api.FilterSourceFile(
1771 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531772 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1773 for line_num, line in fpath.ChangedContents():
1774 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021775 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531776 results.append(output_api.PresubmitError(
1777 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1778 (fpath.LocalPath(), line_num, deprecated_value, value)))
1779 return results
1780
mohan.reddyf21db962014-10-16 12:26:471781
dbeam070cfe62014-10-22 06:44:021782_DEPRECATED_JS = [
1783 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1784 ( "__defineGetter__", "Object.defineProperty" ),
1785 ( "__defineSetter__", "Object.defineProperty" ),
1786]
1787
1788def _CheckNoDeprecatedJS(input_api, output_api):
1789 """Make sure that we don't use deprecated JS in Chrome code."""
1790 results = []
1791 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1792 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1793 input_api.DEFAULT_BLACK_LIST)
1794 file_filter = lambda f: input_api.FilterSourceFile(
1795 f, white_list=file_inclusion_pattern, black_list=black_list)
1796 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1797 for lnum, line in fpath.ChangedContents():
1798 for (deprecated, replacement) in _DEPRECATED_JS:
1799 if deprecated in line:
1800 results.append(output_api.PresubmitError(
1801 "%s:%d: Use of deprecated JS %s, use %s instead" %
1802 (fpath.LocalPath(), lnum, deprecated, replacement)))
1803 return results
1804
1805
dgnaa68d5e2015-06-10 10:08:221806def _AndroidSpecificOnUploadChecks(input_api, output_api):
1807 """Groups checks that target android code."""
1808 results = []
dgnaa68d5e2015-06-10 10:08:221809 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221810 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291811 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221812 return results
1813
1814
[email protected]22c9bd72011-03-27 16:47:391815def _CommonChecks(input_api, output_api):
1816 """Checks common to both upload and commit."""
1817 results = []
1818 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381819 input_api, output_api,
1820 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461821 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191822 results.extend(
[email protected]760deea2013-12-10 19:33:491823 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541824 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181825 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521826 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221827 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441828 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591829 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061830 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121831 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181832 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221833 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491834 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271835 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031836 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491837 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441838 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271839 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541840 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441841 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391842 results.extend(_CheckFlakyTestUsage(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461843 # TODO(danakj): Remove this when base/move.h is removed.
dchengcf95c122015-12-18 08:29:161844 results.extend(_CheckForUsingPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551845 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041846 results.extend(
1847 input_api.canned_checks.CheckChangeHasNoTabs(
1848 input_api,
1849 output_api,
1850 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401851 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161852 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591853 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081854 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531855 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021856 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471857 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041858 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361859 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231860 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431861 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201862 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401863 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241864
1865 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1866 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1867 input_api, output_api,
1868 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381869 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391870 return results
[email protected]1f7b4172010-01-28 01:17:341871
[email protected]b337cb5b2011-01-23 21:24:051872
[email protected]66daa702011-05-28 14:41:461873def _CheckAuthorizedAuthor(input_api, output_api):
1874 """For non-googler/chromites committers, verify the author's email address is
1875 in AUTHORS.
1876 """
[email protected]9bb9cb82011-06-13 20:43:011877 # TODO(maruel): Add it to input_api?
1878 import fnmatch
1879
[email protected]66daa702011-05-28 14:41:461880 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011881 if not author:
1882 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461883 return []
[email protected]c99663292011-05-31 19:46:081884 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461885 input_api.PresubmitLocalPath(), 'AUTHORS')
1886 valid_authors = (
1887 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1888 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181889 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441890 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231891 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461892 return [output_api.PresubmitPromptWarning(
1893 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1894 '\n'
1895 'http://www.chromium.org/developers/contributing-code and read the '
1896 '"Legal" section\n'
1897 'If you are a chromite, verify the contributor signed the CLA.') %
1898 author)]
1899 return []
1900
1901
[email protected]b8079ae4a2012-12-05 19:56:491902def _CheckPatchFiles(input_api, output_api):
1903 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1904 if f.LocalPath().endswith(('.orig', '.rej'))]
1905 if problems:
1906 return [output_api.PresubmitError(
1907 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031908 else:
1909 return []
[email protected]b8079ae4a2012-12-05 19:56:491910
1911
[email protected]b00342e7f2013-03-26 16:21:541912def _DidYouMeanOSMacro(bad_macro):
1913 try:
1914 return {'A': 'OS_ANDROID',
1915 'B': 'OS_BSD',
1916 'C': 'OS_CHROMEOS',
1917 'F': 'OS_FREEBSD',
1918 'L': 'OS_LINUX',
1919 'M': 'OS_MACOSX',
1920 'N': 'OS_NACL',
1921 'O': 'OS_OPENBSD',
1922 'P': 'OS_POSIX',
1923 'S': 'OS_SOLARIS',
1924 'W': 'OS_WIN'}[bad_macro[3].upper()]
1925 except KeyError:
1926 return ''
1927
1928
1929def _CheckForInvalidOSMacrosInFile(input_api, f):
1930 """Check for sensible looking, totally invalid OS macros."""
1931 preprocessor_statement = input_api.re.compile(r'^\s*#')
1932 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1933 results = []
1934 for lnum, line in f.ChangedContents():
1935 if preprocessor_statement.search(line):
1936 for match in os_macro.finditer(line):
1937 if not match.group(1) in _VALID_OS_MACROS:
1938 good = _DidYouMeanOSMacro(match.group(1))
1939 did_you_mean = ' (did you mean %s?)' % good if good else ''
1940 results.append(' %s:%d %s%s' % (f.LocalPath(),
1941 lnum,
1942 match.group(1),
1943 did_you_mean))
1944 return results
1945
1946
1947def _CheckForInvalidOSMacros(input_api, output_api):
1948 """Check all affected files for invalid OS macros."""
1949 bad_macros = []
1950 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:471951 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:541952 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1953
1954 if not bad_macros:
1955 return []
1956
1957 return [output_api.PresubmitError(
1958 'Possibly invalid OS macro[s] found. Please fix your code\n'
1959 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1960
lliabraa35bab3932014-10-01 12:16:441961
1962def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1963 """Check all affected files for invalid "if defined" macros."""
1964 ALWAYS_DEFINED_MACROS = (
1965 "TARGET_CPU_PPC",
1966 "TARGET_CPU_PPC64",
1967 "TARGET_CPU_68K",
1968 "TARGET_CPU_X86",
1969 "TARGET_CPU_ARM",
1970 "TARGET_CPU_MIPS",
1971 "TARGET_CPU_SPARC",
1972 "TARGET_CPU_ALPHA",
1973 "TARGET_IPHONE_SIMULATOR",
1974 "TARGET_OS_EMBEDDED",
1975 "TARGET_OS_IPHONE",
1976 "TARGET_OS_MAC",
1977 "TARGET_OS_UNIX",
1978 "TARGET_OS_WIN32",
1979 )
1980 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1981 results = []
1982 for lnum, line in f.ChangedContents():
1983 for match in ifdef_macro.finditer(line):
1984 if match.group(1) in ALWAYS_DEFINED_MACROS:
1985 always_defined = ' %s is always defined. ' % match.group(1)
1986 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1987 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1988 lnum,
1989 always_defined,
1990 did_you_mean))
1991 return results
1992
1993
1994def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1995 """Check all affected files for invalid "if defined" macros."""
1996 bad_macros = []
1997 for f in input_api.AffectedFiles():
1998 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1999 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2000
2001 if not bad_macros:
2002 return []
2003
2004 return [output_api.PresubmitError(
2005 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2006 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2007 bad_macros)]
2008
2009
dchengcf95c122015-12-18 08:29:162010def _CheckForUsingPass(input_api, output_api):
danakj3c84d0c2014-10-06 15:35:462011 """Check all affected files for using side effects of Pass."""
2012 errors = []
2013 for f in input_api.AffectedFiles():
2014 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2015 for lnum, line in f.ChangedContents():
dchengcf95c122015-12-18 08:29:162016 # Warn on any use of foo.Pass().
2017 if input_api.re.search(r'[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:462018 errors.append(output_api.PresubmitError(
dchengcf95c122015-12-18 08:29:162019 ('%s:%d uses Pass(); please use std::move() instead. ' +
2020 'See crbug.com/557422.') % (f.LocalPath(), lnum)))
danakj3c84d0c2014-10-06 15:35:462021 return errors
2022
2023
mlamouria82272622014-09-16 18:45:042024def _CheckForIPCRules(input_api, output_api):
2025 """Check for same IPC rules described in
2026 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2027 """
2028 base_pattern = r'IPC_ENUM_TRAITS\('
2029 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2030 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2031
2032 problems = []
2033 for f in input_api.AffectedSourceFiles(None):
2034 local_path = f.LocalPath()
2035 if not local_path.endswith('.h'):
2036 continue
2037 for line_number, line in f.ChangedContents():
2038 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2039 problems.append(
2040 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2041
2042 if problems:
2043 return [output_api.PresubmitPromptWarning(
2044 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2045 else:
2046 return []
2047
[email protected]b00342e7f2013-03-26 16:21:542048
mostynbb639aca52015-01-07 20:31:232049def _CheckForWindowsLineEndings(input_api, output_api):
2050 """Check source code and known ascii text files for Windows style line
2051 endings.
2052 """
earthdok1b5e0ee2015-03-10 15:19:102053 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232054
2055 file_inclusion_pattern = (
2056 known_text_files,
2057 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2058 )
2059
2060 filter = lambda f: input_api.FilterSourceFile(
2061 f, white_list=file_inclusion_pattern, black_list=None)
2062 files = [f.LocalPath() for f in
2063 input_api.AffectedSourceFiles(filter)]
2064
2065 problems = []
2066
2067 for file in files:
2068 fp = open(file, 'r')
2069 for line in fp:
2070 if line.endswith('\r\n'):
2071 problems.append(file)
2072 break
2073 fp.close()
2074
2075 if problems:
2076 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2077 'these files to contain Windows style line endings?\n' +
2078 '\n'.join(problems))]
2079
2080 return []
2081
2082
[email protected]1f7b4172010-01-28 01:17:342083def CheckChangeOnUpload(input_api, output_api):
2084 results = []
2085 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472086 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:172087 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:282088 results.extend(
2089 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192090 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222091 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542092 return results
[email protected]ca8d19842009-02-19 16:33:122093
2094
[email protected]1bfb8322014-04-23 01:02:412095def GetTryServerMasterForBot(bot):
2096 """Returns the Try Server master for the given bot.
2097
[email protected]0bb112362014-07-26 04:38:322098 It tries to guess the master from the bot name, but may still fail
2099 and return None. There is no longer a default master.
2100 """
2101 # Potentially ambiguous bot names are listed explicitly.
2102 master_map = {
[email protected]0bb112362014-07-26 04:38:322103 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322104 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412105 }
[email protected]0bb112362014-07-26 04:38:322106 master = master_map.get(bot)
2107 if not master:
sergiyb37fd293f2015-02-26 06:55:012108 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322109 master = 'tryserver.chromium.linux'
2110 elif 'win' in bot:
2111 master = 'tryserver.chromium.win'
2112 elif 'mac' in bot or 'ios' in bot:
2113 master = 'tryserver.chromium.mac'
2114 return master
[email protected]1bfb8322014-04-23 01:02:412115
2116
Paweł Hajdan, Jr55083782014-12-19 20:32:562117def GetDefaultTryConfigs(bots):
2118 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012119 """
2120
Paweł Hajdan, Jr55083782014-12-19 20:32:562121 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412122
2123 # Build up the mapping from tryserver master to bot/test.
2124 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562125 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412126 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2127 return out
[email protected]38c6a512013-12-18 23:48:012128
2129
[email protected]ca8d19842009-02-19 16:33:122130def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542131 results = []
[email protected]1f7b4172010-01-28 01:17:342132 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542133 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272134 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342135 input_api,
2136 output_api,
[email protected]2fdd1f362013-01-16 03:56:032137 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272138
[email protected]3e4eb112011-01-18 03:29:542139 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2140 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412141 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2142 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542143 return results