blob: 949e03aed1160497daa1e6ec013f278a263cf47d [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
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]ca8d1982009-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]ca8d1982009-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$",
[email protected]7345da02012-11-27 14:31:49187 ),
[email protected]23e6cbc2012-06-16 18:51:20188 ),
[email protected]52657f62013-05-20 05:30:31189 (
tomhudson7e6e0512016-04-19 19:27:22190 'skia::RefPtr',
191 (
192 'The use of skia::RefPtr is prohibited. ',
193 'Please use sk_sp<> instead.'
194 ),
195 True,
196 (),
197 ),
198 (
[email protected]52657f62013-05-20 05:30:31199 'SkRefPtr',
200 (
201 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22202 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31203 ),
204 True,
205 (),
206 ),
207 (
208 'SkAutoRef',
209 (
210 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22211 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31212 ),
213 True,
214 (),
215 ),
216 (
217 'SkAutoTUnref',
218 (
219 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22220 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31221 ),
222 True,
223 (),
224 ),
225 (
226 'SkAutoUnref',
227 (
228 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
229 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22230 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31231 ),
232 True,
233 (),
234 ),
[email protected]d89eec82013-12-03 14:10:59235 (
236 r'/HANDLE_EINTR\(.*close',
237 (
238 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
239 'descriptor will be closed, and it is incorrect to retry the close.',
240 'Either call close directly and ignore its return value, or wrap close',
241 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
242 ),
243 True,
244 (),
245 ),
246 (
247 r'/IGNORE_EINTR\((?!.*close)',
248 (
249 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
250 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
251 ),
252 True,
253 (
254 # Files that #define IGNORE_EINTR.
255 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
256 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
257 ),
258 ),
[email protected]ec5b3f02014-04-04 18:43:43259 (
260 r'/v8::Extension\(',
261 (
262 'Do not introduce new v8::Extensions into the code base, use',
263 'gin::Wrappable instead. See http://crbug.com/334679',
264 ),
265 True,
[email protected]f55c90ee62014-04-12 00:50:03266 (
joaodasilva718f87672014-08-30 09:25:49267 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03268 ),
[email protected]ec5b3f02014-04-04 18:43:43269 ),
skyostilf9469f72015-04-20 10:38:52270 (
sdefresneeaeccc52015-04-22 08:18:32271 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52272 (
273 'MessageLoopProxy is deprecated. ',
274 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
275 ),
276 True,
kinuko59024ce2015-04-21 22:18:30277 (
278 # Internal message_loop related code may still use it.
279 r'^base[\\\/]message_loop[\\\/].*',
280 ),
skyostilf9469f72015-04-20 10:38:52281 ),
jame2d1a952016-04-02 00:27:10282 (
283 '#pragma comment(lib,',
284 (
285 'Specify libraries to link with in build files and not in the source.',
286 ),
287 True,
288 (),
289 ),
[email protected]127f18ec2012-06-16 05:05:59290)
291
mlamouria82272622014-09-16 18:45:04292_IPC_ENUM_TRAITS_DEPRECATED = (
293 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
294 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
295
[email protected]127f18ec2012-06-16 05:05:59296
[email protected]b00342e7f2013-03-26 16:21:54297_VALID_OS_MACROS = (
298 # Please keep sorted.
299 'OS_ANDROID',
300 'OS_BSD',
301 'OS_CAT', # For testing.
302 'OS_CHROMEOS',
303 'OS_FREEBSD',
304 'OS_IOS',
305 'OS_LINUX',
306 'OS_MACOSX',
307 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21308 'OS_NACL_NONSFI',
309 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54310 'OS_OPENBSD',
311 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37312 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54313 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54314 'OS_WIN',
315)
316
317
agrievef32bcc72016-04-04 14:57:40318_ANDROID_SPECIFIC_PYDEPS_FILES = [
319 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19320 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40321]
322
323_GENERIC_PYDEPS_FILES = [
324 'build/secondary/tools/swarming_client/isolate.pydeps',
325]
326
327_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
328
329
[email protected]55459852011-08-10 15:17:19330def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
331 """Attempts to prevent use of functions intended only for testing in
332 non-testing code. For now this is just a best-effort implementation
333 that ignores header files and may have some false positives. A
334 better implementation would probably need a proper C++ parser.
335 """
336 # We only scan .cc files and the like, as the declaration of
337 # for-testing functions in header files are hard to distinguish from
338 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44339 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19340
jochenc0d4808c2015-07-27 09:25:42341 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19342 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09343 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19344 exclusion_pattern = input_api.re.compile(
345 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
346 base_function_pattern, base_function_pattern))
347
348 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44349 black_list = (_EXCLUDED_PATHS +
350 _TEST_CODE_EXCLUDED_PATHS +
351 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19352 return input_api.FilterSourceFile(
353 affected_file,
354 white_list=(file_inclusion_pattern, ),
355 black_list=black_list)
356
357 problems = []
358 for f in input_api.AffectedSourceFiles(FilterFile):
359 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24360 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03361 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46362 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03363 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19364 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03365 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19366
367 if problems:
[email protected]f7051d52013-04-02 18:31:42368 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03369 else:
370 return []
[email protected]55459852011-08-10 15:17:19371
372
[email protected]10689ca2011-09-02 02:31:54373def _CheckNoIOStreamInHeaders(input_api, output_api):
374 """Checks to make sure no .h files include <iostream>."""
375 files = []
376 pattern = input_api.re.compile(r'^#include\s*<iostream>',
377 input_api.re.MULTILINE)
378 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
379 if not f.LocalPath().endswith('.h'):
380 continue
381 contents = input_api.ReadFile(f)
382 if pattern.search(contents):
383 files.append(f)
384
385 if len(files):
yolandyandaabc6d2016-04-18 18:29:39386 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06387 'Do not #include <iostream> in header files, since it inserts static '
388 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54389 '#include <ostream>. See http://crbug.com/94794',
390 files) ]
391 return []
392
393
[email protected]72df4e782012-06-21 16:28:18394def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52395 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18396 problems = []
397 for f in input_api.AffectedFiles():
398 if (not f.LocalPath().endswith(('.cc', '.mm'))):
399 continue
400
401 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04402 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18403 problems.append(' %s:%d' % (f.LocalPath(), line_num))
404
405 if not problems:
406 return []
407 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
408 '\n'.join(problems))]
409
410
danakj61c1aa22015-10-26 19:55:52411def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
412 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
413 errors = []
414 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
415 input_api.re.MULTILINE)
416 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
417 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
418 continue
419 for lnum, line in f.ChangedContents():
420 if input_api.re.search(pattern, line):
421 errors.append(output_api.PresubmitError(
422 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
423 'DCHECK_IS_ON()", not forgetting the braces.')
424 % (f.LocalPath(), lnum)))
425 return errors
426
427
mcasasb7440c282015-02-04 14:52:19428def _FindHistogramNameInLine(histogram_name, line):
429 """Tries to find a histogram name or prefix in a line."""
430 if not "affected-histogram" in line:
431 return histogram_name in line
432 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
433 # the histogram_name.
434 if not '"' in line:
435 return False
436 histogram_prefix = line.split('\"')[1]
437 return histogram_prefix in histogram_name
438
439
440def _CheckUmaHistogramChanges(input_api, output_api):
441 """Check that UMA histogram names in touched lines can still be found in other
442 lines of the patch or in histograms.xml. Note that this check would not catch
443 the reverse: changes in histograms.xml not matched in the code itself."""
444 touched_histograms = []
445 histograms_xml_modifications = []
446 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
447 for f in input_api.AffectedFiles():
448 # If histograms.xml itself is modified, keep the modified lines for later.
449 if f.LocalPath().endswith(('histograms.xml')):
450 histograms_xml_modifications = f.ChangedContents()
451 continue
452 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
453 continue
454 for line_num, line in f.ChangedContents():
455 found = pattern.search(line)
456 if found:
457 touched_histograms.append([found.group(1), f, line_num])
458
459 # Search for the touched histogram names in the local modifications to
460 # histograms.xml, and, if not found, on the base histograms.xml file.
461 unmatched_histograms = []
462 for histogram_info in touched_histograms:
463 histogram_name_found = False
464 for line_num, line in histograms_xml_modifications:
465 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
466 if histogram_name_found:
467 break
468 if not histogram_name_found:
469 unmatched_histograms.append(histogram_info)
470
eromanb90c82e7e32015-04-01 15:13:49471 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19472 problems = []
473 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49474 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19475 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45476 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19477 histogram_name_found = False
478 for line in histograms_xml:
479 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
480 if histogram_name_found:
481 break
482 if not histogram_name_found:
483 problems.append(' [%s:%d] %s' %
484 (f.LocalPath(), line_num, histogram_name))
485
486 if not problems:
487 return []
488 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
489 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49490 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19491
yolandyandaabc6d2016-04-18 18:29:39492def _CheckFlakyTestUsage(input_api, output_api):
493 """Check that FlakyTest annotation is our own instead of the android one"""
494 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
495 files = []
496 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
497 if f.LocalPath().endswith('Test.java'):
498 if pattern.search(input_api.ReadFile(f)):
499 files.append(f)
500 if len(files):
501 return [output_api.PresubmitError(
502 'Use org.chromium.base.test.util.FlakyTest instead of '
503 'android.test.FlakyTest',
504 files)]
505 return []
mcasasb7440c282015-02-04 14:52:19506
[email protected]8ea5d4b2011-09-13 21:49:22507def _CheckNoNewWStrings(input_api, output_api):
508 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27509 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22510 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20511 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57512 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
513 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20514 continue
[email protected]8ea5d4b2011-09-13 21:49:22515
[email protected]a11dbe9b2012-08-07 01:32:58516 allowWString = False
[email protected]b5c24292011-11-28 14:38:20517 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58518 if 'presubmit: allow wstring' in line:
519 allowWString = True
520 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27521 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58522 allowWString = False
523 else:
524 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22525
[email protected]55463aa62011-10-12 00:48:27526 if not problems:
527 return []
528 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58529 ' If you are calling a cross-platform API that accepts a wstring, '
530 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27531 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22532
533
[email protected]2a8ac9c2011-10-19 17:20:44534def _CheckNoDEPSGIT(input_api, output_api):
535 """Make sure .DEPS.git is never modified manually."""
536 if any(f.LocalPath().endswith('.DEPS.git') for f in
537 input_api.AffectedFiles()):
538 return [output_api.PresubmitError(
539 'Never commit changes to .DEPS.git. This file is maintained by an\n'
540 'automated system based on what\'s in DEPS and your changes will be\n'
541 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34542 '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:44543 'for more information')]
544 return []
545
546
tandriief664692014-09-23 14:51:47547def _CheckValidHostsInDEPS(input_api, output_api):
548 """Checks that DEPS file deps are from allowed_hosts."""
549 # Run only if DEPS file has been modified to annoy fewer bystanders.
550 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
551 return []
552 # Outsource work to gclient verify
553 try:
554 input_api.subprocess.check_output(['gclient', 'verify'])
555 return []
556 except input_api.subprocess.CalledProcessError, error:
557 return [output_api.PresubmitError(
558 'DEPS file must have only git dependencies.',
559 long_text=error.output)]
560
561
[email protected]127f18ec2012-06-16 05:05:59562def _CheckNoBannedFunctions(input_api, output_api):
563 """Make sure that banned functions are not used."""
564 warnings = []
565 errors = []
566
567 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
568 for f in input_api.AffectedFiles(file_filter=file_filter):
569 for line_num, line in f.ChangedContents():
570 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26571 matched = False
572 if func_name[0:1] == '/':
573 regex = func_name[1:]
574 if input_api.re.search(regex, line):
575 matched = True
576 elif func_name in line:
577 matched = True
578 if matched:
[email protected]127f18ec2012-06-16 05:05:59579 problems = warnings;
580 if error:
581 problems = errors;
582 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
583 for message_line in message:
584 problems.append(' %s' % message_line)
585
586 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
587 for f in input_api.AffectedFiles(file_filter=file_filter):
588 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49589 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
590 def IsBlacklisted(affected_file, blacklist):
591 local_path = affected_file.LocalPath()
592 for item in blacklist:
593 if input_api.re.match(item, local_path):
594 return True
595 return False
596 if IsBlacklisted(f, excluded_paths):
597 continue
[email protected]d89eec82013-12-03 14:10:59598 matched = False
599 if func_name[0:1] == '/':
600 regex = func_name[1:]
601 if input_api.re.search(regex, line):
602 matched = True
603 elif func_name in line:
604 matched = True
605 if matched:
[email protected]127f18ec2012-06-16 05:05:59606 problems = warnings;
607 if error:
608 problems = errors;
609 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
610 for message_line in message:
611 problems.append(' %s' % message_line)
612
613 result = []
614 if (warnings):
615 result.append(output_api.PresubmitPromptWarning(
616 'Banned functions were used.\n' + '\n'.join(warnings)))
617 if (errors):
618 result.append(output_api.PresubmitError(
619 'Banned functions were used.\n' + '\n'.join(errors)))
620 return result
621
622
[email protected]6c063c62012-07-11 19:11:06623def _CheckNoPragmaOnce(input_api, output_api):
624 """Make sure that banned functions are not used."""
625 files = []
626 pattern = input_api.re.compile(r'^#pragma\s+once',
627 input_api.re.MULTILINE)
628 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
629 if not f.LocalPath().endswith('.h'):
630 continue
631 contents = input_api.ReadFile(f)
632 if pattern.search(contents):
633 files.append(f)
634
635 if files:
636 return [output_api.PresubmitError(
637 'Do not use #pragma once in header files.\n'
638 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
639 files)]
640 return []
641
[email protected]127f18ec2012-06-16 05:05:59642
[email protected]e7479052012-09-19 00:26:12643def _CheckNoTrinaryTrueFalse(input_api, output_api):
644 """Checks to make sure we don't introduce use of foo ? true : false."""
645 problems = []
646 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
647 for f in input_api.AffectedFiles():
648 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
649 continue
650
651 for line_num, line in f.ChangedContents():
652 if pattern.match(line):
653 problems.append(' %s:%d' % (f.LocalPath(), line_num))
654
655 if not problems:
656 return []
657 return [output_api.PresubmitPromptWarning(
658 'Please consider avoiding the "? true : false" pattern if possible.\n' +
659 '\n'.join(problems))]
660
661
[email protected]55f9f382012-07-31 11:02:18662def _CheckUnwantedDependencies(input_api, output_api):
663 """Runs checkdeps on #include statements added in this
664 change. Breaking - rules is an error, breaking ! rules is a
665 warning.
666 """
mohan.reddyf21db962014-10-16 12:26:47667 import sys
[email protected]55f9f382012-07-31 11:02:18668 # We need to wait until we have an input_api object and use this
669 # roundabout construct to import checkdeps because this file is
670 # eval-ed and thus doesn't have __file__.
671 original_sys_path = sys.path
672 try:
673 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47674 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18675 import checkdeps
676 from cpp_checker import CppChecker
677 from rules import Rule
678 finally:
679 # Restore sys.path to what it was before.
680 sys.path = original_sys_path
681
682 added_includes = []
683 for f in input_api.AffectedFiles():
684 if not CppChecker.IsCppFile(f.LocalPath()):
685 continue
686
687 changed_lines = [line for line_num, line in f.ChangedContents()]
688 added_includes.append([f.LocalPath(), changed_lines])
689
[email protected]26385172013-05-09 23:11:35690 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18691
692 error_descriptions = []
693 warning_descriptions = []
694 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
695 added_includes):
696 description_with_path = '%s\n %s' % (path, rule_description)
697 if rule_type == Rule.DISALLOW:
698 error_descriptions.append(description_with_path)
699 else:
700 warning_descriptions.append(description_with_path)
701
702 results = []
703 if error_descriptions:
704 results.append(output_api.PresubmitError(
705 'You added one or more #includes that violate checkdeps rules.',
706 error_descriptions))
707 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42708 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18709 'You added one or more #includes of files that are temporarily\n'
710 'allowed but being removed. Can you avoid introducing the\n'
711 '#include? See relevant DEPS file(s) for details and contacts.',
712 warning_descriptions))
713 return results
714
715
[email protected]fbcafe5a2012-08-08 15:31:22716def _CheckFilePermissions(input_api, output_api):
717 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15718 if input_api.platform == 'win32':
719 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29720 checkperms_tool = input_api.os_path.join(
721 input_api.PresubmitLocalPath(),
722 'tools', 'checkperms', 'checkperms.py')
723 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47724 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22725 for f in input_api.AffectedFiles():
726 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11727 try:
728 input_api.subprocess.check_output(args)
729 return []
730 except input_api.subprocess.CalledProcessError as error:
731 return [output_api.PresubmitError(
732 'checkperms.py failed:',
733 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22734
735
[email protected]c8278b32012-10-30 20:35:49736def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
737 """Makes sure we don't include ui/aura/window_property.h
738 in header files.
739 """
740 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
741 errors = []
742 for f in input_api.AffectedFiles():
743 if not f.LocalPath().endswith('.h'):
744 continue
745 for line_num, line in f.ChangedContents():
746 if pattern.match(line):
747 errors.append(' %s:%d' % (f.LocalPath(), line_num))
748
749 results = []
750 if errors:
751 results.append(output_api.PresubmitError(
752 'Header files should not include ui/aura/window_property.h', errors))
753 return results
754
755
[email protected]cf9b78f2012-11-14 11:40:28756def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
757 """Checks that the lines in scope occur in the right order.
758
759 1. C system files in alphabetical order
760 2. C++ system files in alphabetical order
761 3. Project's .h files
762 """
763
764 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
765 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
766 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
767
768 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
769
770 state = C_SYSTEM_INCLUDES
771
772 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57773 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28774 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55775 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28776 for line_num, line in scope:
777 if c_system_include_pattern.match(line):
778 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55779 problem_linenums.append((line_num, previous_line_num,
780 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28781 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55782 problem_linenums.append((line_num, previous_line_num,
783 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28784 elif cpp_system_include_pattern.match(line):
785 if state == C_SYSTEM_INCLUDES:
786 state = CPP_SYSTEM_INCLUDES
787 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55788 problem_linenums.append((line_num, previous_line_num,
789 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28790 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55791 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28792 elif custom_include_pattern.match(line):
793 if state != CUSTOM_INCLUDES:
794 state = CUSTOM_INCLUDES
795 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55796 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28797 else:
brucedawson70fadb02015-06-30 17:47:55798 problem_linenums.append((line_num, previous_line_num,
799 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28800 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57801 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28802
803 warnings = []
brucedawson70fadb02015-06-30 17:47:55804 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57805 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55806 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28807 return warnings
808
809
[email protected]ac294a12012-12-06 16:38:43810def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28811 """Checks the #include order for the given file f."""
812
[email protected]2299dcf2012-11-15 19:56:24813 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30814 # Exclude the following includes from the check:
815 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
816 # specific order.
817 # 2) <atlbase.h>, "build/build_config.h"
818 excluded_include_pattern = input_api.re.compile(
819 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24820 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33821 # Match the final or penultimate token if it is xxxtest so we can ignore it
822 # when considering the special first include.
823 test_file_tag_pattern = input_api.re.compile(
824 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11825 if_pattern = input_api.re.compile(
826 r'\s*#\s*(if|elif|else|endif|define|undef).*')
827 # Some files need specialized order of includes; exclude such files from this
828 # check.
829 uncheckable_includes_pattern = input_api.re.compile(
830 r'\s*#include '
831 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28832
833 contents = f.NewContents()
834 warnings = []
835 line_num = 0
836
[email protected]ac294a12012-12-06 16:38:43837 # Handle the special first include. If the first include file is
838 # some/path/file.h, the corresponding including file can be some/path/file.cc,
839 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
840 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33841 # If the included file is some/path/file_platform.h the including file could
842 # also be some/path/file_xxxtest_platform.h.
843 including_file_base_name = test_file_tag_pattern.sub(
844 '', input_api.os_path.basename(f.LocalPath()))
845
[email protected]ac294a12012-12-06 16:38:43846 for line in contents:
847 line_num += 1
848 if system_include_pattern.match(line):
849 # No special first include -> process the line again along with normal
850 # includes.
851 line_num -= 1
852 break
853 match = custom_include_pattern.match(line)
854 if match:
855 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33856 header_basename = test_file_tag_pattern.sub(
857 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
858
859 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24860 # No special first include -> process the line again along with normal
861 # includes.
862 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43863 break
[email protected]cf9b78f2012-11-14 11:40:28864
865 # Split into scopes: Each region between #if and #endif is its own scope.
866 scopes = []
867 current_scope = []
868 for line in contents[line_num:]:
869 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11870 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54871 continue
[email protected]2309b0fa02012-11-16 12:18:27872 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28873 scopes.append(current_scope)
874 current_scope = []
[email protected]962f117e2012-11-22 18:11:56875 elif ((system_include_pattern.match(line) or
876 custom_include_pattern.match(line)) and
877 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28878 current_scope.append((line_num, line))
879 scopes.append(current_scope)
880
881 for scope in scopes:
882 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
883 changed_linenums))
884 return warnings
885
886
887def _CheckIncludeOrder(input_api, output_api):
888 """Checks that the #include order is correct.
889
890 1. The corresponding header for source files.
891 2. C system files in alphabetical order
892 3. C++ system files in alphabetical order
893 4. Project's .h files in alphabetical order
894
[email protected]ac294a12012-12-06 16:38:43895 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
896 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28897 """
[email protected]e120b012014-08-15 19:08:35898 def FileFilterIncludeOrder(affected_file):
899 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
900 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28901
902 warnings = []
[email protected]e120b012014-08-15 19:08:35903 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08904 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43905 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
906 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28907
908 results = []
909 if warnings:
[email protected]f7051d52013-04-02 18:31:42910 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53911 warnings))
[email protected]cf9b78f2012-11-14 11:40:28912 return results
913
914
[email protected]70ca77752012-11-20 03:45:03915def _CheckForVersionControlConflictsInFile(input_api, f):
916 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
917 errors = []
918 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23919 if f.LocalPath().endswith('.md'):
920 # First-level headers in markdown look a lot like version control
921 # conflict markers. http://daringfireball.net/projects/markdown/basics
922 continue
[email protected]70ca77752012-11-20 03:45:03923 if pattern.match(line):
924 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
925 return errors
926
927
928def _CheckForVersionControlConflicts(input_api, output_api):
929 """Usually this is not intentional and will cause a compile failure."""
930 errors = []
931 for f in input_api.AffectedFiles():
932 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
933
934 results = []
935 if errors:
936 results.append(output_api.PresubmitError(
937 'Version control conflict markers found, please resolve.', errors))
938 return results
939
940
[email protected]06e6d0ff2012-12-11 01:36:44941def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
942 def FilterFile(affected_file):
943 """Filter function for use with input_api.AffectedSourceFiles,
944 below. This filters out everything except non-test files from
945 top-level directories that generally speaking should not hard-code
946 service URLs (e.g. src/android_webview/, src/content/ and others).
947 """
948 return input_api.FilterSourceFile(
949 affected_file,
[email protected]78bb39d62012-12-11 15:11:56950 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44951 black_list=(_EXCLUDED_PATHS +
952 _TEST_CODE_EXCLUDED_PATHS +
953 input_api.DEFAULT_BLACK_LIST))
954
reillyi38965732015-11-16 18:27:33955 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
956 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46957 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
958 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44959 problems = [] # items are (filename, line_number, line)
960 for f in input_api.AffectedSourceFiles(FilterFile):
961 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46962 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44963 problems.append((f.LocalPath(), line_num, line))
964
965 if problems:
[email protected]f7051d52013-04-02 18:31:42966 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44967 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58968 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44969 [' %s:%d: %s' % (
970 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03971 else:
972 return []
[email protected]06e6d0ff2012-12-11 01:36:44973
974
[email protected]d2530012013-01-25 16:39:27975def _CheckNoAbbreviationInPngFileName(input_api, output_api):
976 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31977 The native_client_sdk directory is excluded because it has auto-generated PNG
978 files for documentation.
[email protected]d2530012013-01-25 16:39:27979 """
[email protected]d2530012013-01-25 16:39:27980 errors = []
binji0dcdf342014-12-12 18:32:31981 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
982 black_list = (r'^native_client_sdk[\\\/]',)
983 file_filter = lambda f: input_api.FilterSourceFile(
984 f, white_list=white_list, black_list=black_list)
985 for f in input_api.AffectedFiles(include_deletes=False,
986 file_filter=file_filter):
987 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27988
989 results = []
990 if errors:
991 results.append(output_api.PresubmitError(
992 'The name of PNG files should not have abbreviations. \n'
993 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
994 'Contact [email protected] if you have questions.', errors))
995 return results
996
997
[email protected]14a6131c2014-01-08 01:15:41998def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08999 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411000 a set of DEPS entries that we should look up.
1001
1002 For a directory (rather than a specific filename) we fake a path to
1003 a specific filename by adding /DEPS. This is chosen as a file that
1004 will seldom or never be subject to per-file include_rules.
1005 """
[email protected]2b438d62013-11-14 17:54:141006 # We ignore deps entries on auto-generated directories.
1007 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081008
1009 # This pattern grabs the path without basename in the first
1010 # parentheses, and the basename (if present) in the second. It
1011 # relies on the simple heuristic that if there is a basename it will
1012 # be a header file ending in ".h".
1013 pattern = re.compile(
1014 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141015 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081016 for changed_line in changed_lines:
1017 m = pattern.match(changed_line)
1018 if m:
1019 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141020 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411021 if m.group(2):
1022 results.add('%s%s' % (path, m.group(2)))
1023 else:
1024 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081025 return results
1026
1027
[email protected]e871964c2013-05-13 14:14:551028def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1029 """When a dependency prefixed with + is added to a DEPS file, we
1030 want to make sure that the change is reviewed by an OWNER of the
1031 target file or directory, to avoid layering violations from being
1032 introduced. This check verifies that this happens.
1033 """
1034 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241035
1036 file_filter = lambda f: not input_api.re.match(
1037 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1038 for f in input_api.AffectedFiles(include_deletes=False,
1039 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551040 filename = input_api.os_path.basename(f.LocalPath())
1041 if filename == 'DEPS':
1042 changed_lines |= set(line.strip()
1043 for line_num, line
1044 in f.ChangedContents())
1045 if not changed_lines:
1046 return []
1047
[email protected]14a6131c2014-01-08 01:15:411048 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1049 changed_lines)
[email protected]e871964c2013-05-13 14:14:551050 if not virtual_depended_on_files:
1051 return []
1052
1053 if input_api.is_committing:
1054 if input_api.tbr:
1055 return [output_api.PresubmitNotifyResult(
1056 '--tbr was specified, skipping OWNERS check for DEPS additions')]
1057 if not input_api.change.issue:
1058 return [output_api.PresubmitError(
1059 "DEPS approval by OWNERS check failed: this change has "
1060 "no Rietveld issue number, so we can't check it for approvals.")]
1061 output = output_api.PresubmitError
1062 else:
1063 output = output_api.PresubmitNotifyResult
1064
1065 owners_db = input_api.owners_db
1066 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1067 input_api,
1068 owners_db.email_regexp,
1069 approval_needed=input_api.is_committing)
1070
1071 owner_email = owner_email or input_api.change.author_email
1072
[email protected]de4f7d22013-05-23 14:27:461073 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511074 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461075 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551076 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1077 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411078
1079 # We strip the /DEPS part that was added by
1080 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1081 # directory.
1082 def StripDeps(path):
1083 start_deps = path.rfind('/DEPS')
1084 if start_deps != -1:
1085 return path[:start_deps]
1086 else:
1087 return path
1088 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551089 for path in missing_files]
1090
1091 if unapproved_dependencies:
1092 output_list = [
[email protected]14a6131c2014-01-08 01:15:411093 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551094 '\n '.join(sorted(unapproved_dependencies)))]
1095 if not input_api.is_committing:
1096 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1097 output_list.append(output(
1098 'Suggested missing target path OWNERS:\n %s' %
1099 '\n '.join(suggested_owners or [])))
1100 return output_list
1101
1102 return []
1103
1104
[email protected]85218562013-11-22 07:41:401105def _CheckSpamLogging(input_api, output_api):
1106 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1107 black_list = (_EXCLUDED_PATHS +
1108 _TEST_CODE_EXCLUDED_PATHS +
1109 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501110 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191111 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481112 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461113 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121114 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1115 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581116 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161117 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031118 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151119 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1120 r"^chromecast[\\\/]",
1121 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311122 r"^components[\\\/]html_viewer[\\\/]"
1123 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461124 # TODO(peter): Remove this exception. https://crbug.com/534537
1125 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1126 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251127 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1128 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111129 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151130 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111131 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521132 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501133 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361134 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311135 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131136 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441137 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451138 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021139 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441140 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401141 source_file_filter = lambda x: input_api.FilterSourceFile(
1142 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1143
1144 log_info = []
1145 printf = []
1146
1147 for f in input_api.AffectedSourceFiles(source_file_filter):
1148 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471149 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401150 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471151 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131152 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371153
mohan.reddyf21db962014-10-16 12:26:471154 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371155 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471156 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401157 printf.append(f.LocalPath())
1158
1159 if log_info:
1160 return [output_api.PresubmitError(
1161 'These files spam the console log with LOG(INFO):',
1162 items=log_info)]
1163 if printf:
1164 return [output_api.PresubmitError(
1165 'These files spam the console log with printf/fprintf:',
1166 items=printf)]
1167 return []
1168
1169
[email protected]49aa76a2013-12-04 06:59:161170def _CheckForAnonymousVariables(input_api, output_api):
1171 """These types are all expected to hold locks while in scope and
1172 so should never be anonymous (which causes them to be immediately
1173 destroyed)."""
1174 they_who_must_be_named = [
1175 'base::AutoLock',
1176 'base::AutoReset',
1177 'base::AutoUnlock',
1178 'SkAutoAlphaRestore',
1179 'SkAutoBitmapShaderInstall',
1180 'SkAutoBlitterChoose',
1181 'SkAutoBounderCommit',
1182 'SkAutoCallProc',
1183 'SkAutoCanvasRestore',
1184 'SkAutoCommentBlock',
1185 'SkAutoDescriptor',
1186 'SkAutoDisableDirectionCheck',
1187 'SkAutoDisableOvalCheck',
1188 'SkAutoFree',
1189 'SkAutoGlyphCache',
1190 'SkAutoHDC',
1191 'SkAutoLockColors',
1192 'SkAutoLockPixels',
1193 'SkAutoMalloc',
1194 'SkAutoMaskFreeImage',
1195 'SkAutoMutexAcquire',
1196 'SkAutoPathBoundsUpdate',
1197 'SkAutoPDFRelease',
1198 'SkAutoRasterClipValidate',
1199 'SkAutoRef',
1200 'SkAutoTime',
1201 'SkAutoTrace',
1202 'SkAutoUnref',
1203 ]
1204 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1205 # bad: base::AutoLock(lock.get());
1206 # not bad: base::AutoLock lock(lock.get());
1207 bad_pattern = input_api.re.compile(anonymous)
1208 # good: new base::AutoLock(lock.get())
1209 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1210 errors = []
1211
1212 for f in input_api.AffectedFiles():
1213 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1214 continue
1215 for linenum, line in f.ChangedContents():
1216 if bad_pattern.search(line) and not good_pattern.search(line):
1217 errors.append('%s:%d' % (f.LocalPath(), linenum))
1218
1219 if errors:
1220 return [output_api.PresubmitError(
1221 'These lines create anonymous variables that need to be named:',
1222 items=errors)]
1223 return []
1224
1225
[email protected]5fe0f8742013-11-29 01:04:591226def _CheckCygwinShell(input_api, output_api):
1227 source_file_filter = lambda x: input_api.FilterSourceFile(
1228 x, white_list=(r'.+\.(gyp|gypi)$',))
1229 cygwin_shell = []
1230
1231 for f in input_api.AffectedSourceFiles(source_file_filter):
1232 for linenum, line in f.ChangedContents():
1233 if 'msvs_cygwin_shell' in line:
1234 cygwin_shell.append(f.LocalPath())
1235 break
1236
1237 if cygwin_shell:
1238 return [output_api.PresubmitError(
1239 'These files should not use msvs_cygwin_shell (the default is 0):',
1240 items=cygwin_shell)]
1241 return []
1242
[email protected]85218562013-11-22 07:41:401243
[email protected]999261d2014-03-03 20:08:081244def _CheckUserActionUpdate(input_api, output_api):
1245 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521246 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081247 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521248 # If actions.xml is already included in the changelist, the PRESUBMIT
1249 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081250 return []
1251
[email protected]999261d2014-03-03 20:08:081252 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1253 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521254 current_actions = None
[email protected]999261d2014-03-03 20:08:081255 for f in input_api.AffectedFiles(file_filter=file_filter):
1256 for line_num, line in f.ChangedContents():
1257 match = input_api.re.search(action_re, line)
1258 if match:
[email protected]2f92dec2014-03-07 19:21:521259 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1260 # loaded only once.
1261 if not current_actions:
1262 with open('tools/metrics/actions/actions.xml') as actions_f:
1263 current_actions = actions_f.read()
1264 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081265 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521266 action = 'name="{0}"'.format(action_name)
1267 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081268 return [output_api.PresubmitPromptWarning(
1269 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521270 'tools/metrics/actions/actions.xml. Please run '
1271 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081272 % (f.LocalPath(), line_num, action_name))]
1273 return []
1274
1275
[email protected]99171a92014-06-03 08:44:471276def _GetJSONParseError(input_api, filename, eat_comments=True):
1277 try:
1278 contents = input_api.ReadFile(filename)
1279 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131280 import sys
1281 original_sys_path = sys.path
1282 try:
1283 sys.path = sys.path + [input_api.os_path.join(
1284 input_api.PresubmitLocalPath(),
1285 'tools', 'json_comment_eater')]
1286 import json_comment_eater
1287 finally:
1288 sys.path = original_sys_path
1289 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471290
1291 input_api.json.loads(contents)
1292 except ValueError as e:
1293 return e
1294 return None
1295
1296
1297def _GetIDLParseError(input_api, filename):
1298 try:
1299 contents = input_api.ReadFile(filename)
1300 idl_schema = input_api.os_path.join(
1301 input_api.PresubmitLocalPath(),
1302 'tools', 'json_schema_compiler', 'idl_schema.py')
1303 process = input_api.subprocess.Popen(
1304 [input_api.python_executable, idl_schema],
1305 stdin=input_api.subprocess.PIPE,
1306 stdout=input_api.subprocess.PIPE,
1307 stderr=input_api.subprocess.PIPE,
1308 universal_newlines=True)
1309 (_, error) = process.communicate(input=contents)
1310 return error or None
1311 except ValueError as e:
1312 return e
1313
1314
1315def _CheckParseErrors(input_api, output_api):
1316 """Check that IDL and JSON files do not contain syntax errors."""
1317 actions = {
1318 '.idl': _GetIDLParseError,
1319 '.json': _GetJSONParseError,
1320 }
1321 # These paths contain test data and other known invalid JSON files.
1322 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491323 r'test[\\\/]data[\\\/]',
1324 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471325 ]
1326 # Most JSON files are preprocessed and support comments, but these do not.
1327 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491328 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471329 ]
1330 # Only run IDL checker on files in these directories.
1331 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491332 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1333 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471334 ]
1335
1336 def get_action(affected_file):
1337 filename = affected_file.LocalPath()
1338 return actions.get(input_api.os_path.splitext(filename)[1])
1339
1340 def MatchesFile(patterns, path):
1341 for pattern in patterns:
1342 if input_api.re.search(pattern, path):
1343 return True
1344 return False
1345
1346 def FilterFile(affected_file):
1347 action = get_action(affected_file)
1348 if not action:
1349 return False
1350 path = affected_file.LocalPath()
1351
1352 if MatchesFile(excluded_patterns, path):
1353 return False
1354
1355 if (action == _GetIDLParseError and
1356 not MatchesFile(idl_included_patterns, path)):
1357 return False
1358 return True
1359
1360 results = []
1361 for affected_file in input_api.AffectedFiles(
1362 file_filter=FilterFile, include_deletes=False):
1363 action = get_action(affected_file)
1364 kwargs = {}
1365 if (action == _GetJSONParseError and
1366 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1367 kwargs['eat_comments'] = False
1368 parse_error = action(input_api,
1369 affected_file.AbsoluteLocalPath(),
1370 **kwargs)
1371 if parse_error:
1372 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1373 (affected_file.LocalPath(), parse_error)))
1374 return results
1375
1376
[email protected]760deea2013-12-10 19:33:491377def _CheckJavaStyle(input_api, output_api):
1378 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471379 import sys
[email protected]760deea2013-12-10 19:33:491380 original_sys_path = sys.path
1381 try:
1382 sys.path = sys.path + [input_api.os_path.join(
1383 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1384 import checkstyle
1385 finally:
1386 # Restore sys.path to what it was before.
1387 sys.path = original_sys_path
1388
1389 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091390 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511391 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491392
1393
dskiba88634f4e2015-08-14 23:03:291394def _CheckAndroidToastUsage(input_api, output_api):
1395 """Checks that code uses org.chromium.ui.widget.Toast instead of
1396 android.widget.Toast (Chromium Toast doesn't force hardware
1397 acceleration on low-end devices, saving memory).
1398 """
1399 toast_import_pattern = input_api.re.compile(
1400 r'^import android\.widget\.Toast;$')
1401
1402 errors = []
1403
1404 sources = lambda affected_file: input_api.FilterSourceFile(
1405 affected_file,
1406 black_list=(_EXCLUDED_PATHS +
1407 _TEST_CODE_EXCLUDED_PATHS +
1408 input_api.DEFAULT_BLACK_LIST +
1409 (r'^chromecast[\\\/].*',
1410 r'^remoting[\\\/].*')),
1411 white_list=(r'.*\.java$',))
1412
1413 for f in input_api.AffectedSourceFiles(sources):
1414 for line_num, line in f.ChangedContents():
1415 if toast_import_pattern.search(line):
1416 errors.append("%s:%d" % (f.LocalPath(), line_num))
1417
1418 results = []
1419
1420 if errors:
1421 results.append(output_api.PresubmitError(
1422 'android.widget.Toast usage is detected. Android toasts use hardware'
1423 ' acceleration, and can be\ncostly on low-end devices. Please use'
1424 ' org.chromium.ui.widget.Toast instead.\n'
1425 'Contact [email protected] if you have any questions.',
1426 errors))
1427
1428 return results
1429
1430
dgnaa68d5e2015-06-10 10:08:221431def _CheckAndroidCrLogUsage(input_api, output_api):
1432 """Checks that new logs using org.chromium.base.Log:
1433 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511434 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221435 """
1436 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121437 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1438 class_in_base_pattern = input_api.re.compile(
1439 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1440 has_some_log_import_pattern = input_api.re.compile(
1441 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221442 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121443 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221444 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511445 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221446 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221447
Vincent Scheib16d7b272015-09-15 18:09:071448 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221449 'or contact [email protected] for more info.')
1450 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121451
dgnaa68d5e2015-06-10 10:08:221452 tag_decl_errors = []
1453 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121454 tag_errors = []
dgn38736db2015-09-18 19:20:511455 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121456 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221457
1458 for f in input_api.AffectedSourceFiles(sources):
1459 file_content = input_api.ReadFile(f)
1460 has_modified_logs = False
1461
1462 # Per line checks
dgn87d9fb62015-06-12 09:15:121463 if (cr_log_import_pattern.search(file_content) or
1464 (class_in_base_pattern.search(file_content) and
1465 not has_some_log_import_pattern.search(file_content))):
1466 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221467 for line_num, line in f.ChangedContents():
1468
1469 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121470 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221471 if match:
1472 has_modified_logs = True
1473
1474 # Make sure it uses "TAG"
1475 if not match.group('tag') == 'TAG':
1476 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121477 else:
1478 # Report non cr Log function calls in changed lines
1479 for line_num, line in f.ChangedContents():
1480 if log_call_pattern.search(line):
1481 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221482
1483 # Per file checks
1484 if has_modified_logs:
1485 # Make sure the tag is using the "cr" prefix and is not too long
1486 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511487 tag_name = match.group('name') if match else None
1488 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221489 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511490 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221491 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511492 elif '.' in tag_name:
1493 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221494
1495 results = []
1496 if tag_decl_errors:
1497 results.append(output_api.PresubmitPromptWarning(
1498 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511499 '"private static final String TAG = "<package tag>".\n'
1500 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221501 tag_decl_errors))
1502
1503 if tag_length_errors:
1504 results.append(output_api.PresubmitError(
1505 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511506 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221507 tag_length_errors))
1508
1509 if tag_errors:
1510 results.append(output_api.PresubmitPromptWarning(
1511 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1512 tag_errors))
1513
dgn87d9fb62015-06-12 09:15:121514 if util_log_errors:
dgn4401aa52015-04-29 16:26:171515 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121516 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1517 util_log_errors))
1518
dgn38736db2015-09-18 19:20:511519 if tag_with_dot_errors:
1520 results.append(output_api.PresubmitPromptWarning(
1521 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1522 tag_with_dot_errors))
1523
dgn4401aa52015-04-29 16:26:171524 return results
1525
1526
agrieve7b6479d82015-10-07 14:24:221527def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1528 """Checks if MDPI assets are placed in a correct directory."""
1529 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1530 ('/res/drawable/' in f.LocalPath() or
1531 '/res/drawable-ldrtl/' in f.LocalPath()))
1532 errors = []
1533 for f in input_api.AffectedFiles(include_deletes=False,
1534 file_filter=file_filter):
1535 errors.append(' %s' % f.LocalPath())
1536
1537 results = []
1538 if errors:
1539 results.append(output_api.PresubmitError(
1540 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1541 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1542 '/res/drawable-ldrtl/.\n'
1543 'Contact [email protected] if you have questions.', errors))
1544 return results
1545
1546
agrievef32bcc72016-04-04 14:57:401547class PydepsChecker(object):
1548 def __init__(self, input_api, pydeps_files):
1549 self._file_cache = {}
1550 self._input_api = input_api
1551 self._pydeps_files = pydeps_files
1552
1553 def _LoadFile(self, path):
1554 """Returns the list of paths within a .pydeps file relative to //."""
1555 if path not in self._file_cache:
1556 with open(path) as f:
1557 self._file_cache[path] = f.read()
1558 return self._file_cache[path]
1559
1560 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1561 """Returns an interable of paths within the .pydep, relativized to //."""
1562 os_path = self._input_api.os_path
1563 pydeps_dir = os_path.dirname(pydeps_path)
1564 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1565 if not l.startswith('*'))
1566 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1567
1568 def _CreateFilesToPydepsMap(self):
1569 """Returns a map of local_path -> list_of_pydeps."""
1570 ret = {}
1571 for pydep_local_path in self._pydeps_files:
1572 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1573 ret.setdefault(path, []).append(pydep_local_path)
1574 return ret
1575
1576 def ComputeAffectedPydeps(self):
1577 """Returns an iterable of .pydeps files that might need regenerating."""
1578 affected_pydeps = set()
1579 file_to_pydeps_map = None
1580 for f in self._input_api.AffectedFiles(include_deletes=True):
1581 local_path = f.LocalPath()
1582 if local_path == 'DEPS':
1583 return self._pydeps_files
1584 elif local_path.endswith('.pydeps'):
1585 if local_path in self._pydeps_files:
1586 affected_pydeps.add(local_path)
1587 elif local_path.endswith('.py'):
1588 if file_to_pydeps_map is None:
1589 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1590 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1591 return affected_pydeps
1592
1593 def DetermineIfStale(self, pydeps_path):
1594 """Runs print_python_deps.py to see if the files is stale."""
1595 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1596 cmd = old_pydeps_data[1][1:].strip()
1597 new_pydeps_data = self._input_api.subprocess.check_output(
1598 cmd + ' --output ""', shell=True)
1599 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1600 return cmd
1601
1602
1603def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1604 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001605 # This check is mainly for Android, and involves paths not only in the
1606 # PRESUBMIT.py, but also in the .pydeps files. Just skip it for Windows.
1607 if input_api.platform == 'win32':
1608 return []
agrievef32bcc72016-04-04 14:57:401609 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1610 is_android = input_api.os_path.exists('third_party/android_tools')
1611 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1612 results = []
1613 # First, check for new / deleted .pydeps.
1614 for f in input_api.AffectedFiles(include_deletes=True):
1615 if f.LocalPath().endswith('.pydeps'):
1616 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1617 results.append(output_api.PresubmitError(
1618 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1619 'remove %s' % f.LocalPath()))
1620 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1621 results.append(output_api.PresubmitError(
1622 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1623 'include %s' % f.LocalPath()))
1624
1625 if results:
1626 return results
1627
1628 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1629
1630 for pydep_path in checker.ComputeAffectedPydeps():
1631 try:
1632 cmd = checker.DetermineIfStale(pydep_path)
1633 if cmd:
1634 results.append(output_api.PresubmitError(
1635 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1636 (pydep_path, cmd)))
1637 except input_api.subprocess.CalledProcessError as error:
1638 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1639 long_text=error.output)]
1640
1641 return results
1642
1643
mnaganov9b9b1fe82014-12-11 16:30:361644def _CheckForCopyrightedCode(input_api, output_api):
1645 """Verifies that newly added code doesn't contain copyrighted material
1646 and is properly licensed under the standard Chromium license.
1647
1648 As there can be false positives, we maintain a whitelist file. This check
1649 also verifies that the whitelist file is up to date.
1650 """
1651 import sys
1652 original_sys_path = sys.path
1653 try:
1654 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221655 input_api.PresubmitLocalPath(), 'tools')]
1656 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361657 finally:
1658 # Restore sys.path to what it was before.
1659 sys.path = original_sys_path
1660
1661 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1662
1663
glidere61efad2015-02-18 17:39:431664def _CheckSingletonInHeaders(input_api, output_api):
1665 """Checks to make sure no header files have |Singleton<|."""
1666 def FileFilter(affected_file):
1667 # It's ok for base/memory/singleton.h to have |Singleton<|.
1668 black_list = (_EXCLUDED_PATHS +
1669 input_api.DEFAULT_BLACK_LIST +
1670 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1671 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1672
sergeyu34d21222015-09-16 00:11:441673 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431674 files = []
1675 for f in input_api.AffectedSourceFiles(FileFilter):
1676 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1677 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1678 contents = input_api.ReadFile(f)
1679 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241680 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431681 pattern.search(line)):
1682 files.append(f)
1683 break
1684
1685 if files:
yolandyandaabc6d2016-04-18 18:29:391686 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441687 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431688 'Please move them to an appropriate source file so that the ' +
1689 'template gets instantiated in a single compilation unit.',
1690 files) ]
1691 return []
1692
1693
dbeam37e8e7402016-02-10 22:58:201694def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1695 """Checks for old style compiled_resources.gyp files."""
1696 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1697
1698 added_compiled_resources = filter(is_compiled_resource, [
1699 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1700 ])
1701
1702 if not added_compiled_resources:
1703 return []
1704
1705 return [output_api.PresubmitError(
1706 "Found new compiled_resources.gyp files:\n%s\n\n"
1707 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551708 "please use compiled_resources2.gyp instead:\n"
1709 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1710 %
dbeam37e8e7402016-02-10 22:58:201711 "\n".join(added_compiled_resources))]
1712
1713
[email protected]fd20b902014-05-09 02:14:531714_DEPRECATED_CSS = [
1715 # Values
1716 ( "-webkit-box", "flex" ),
1717 ( "-webkit-inline-box", "inline-flex" ),
1718 ( "-webkit-flex", "flex" ),
1719 ( "-webkit-inline-flex", "inline-flex" ),
1720 ( "-webkit-min-content", "min-content" ),
1721 ( "-webkit-max-content", "max-content" ),
1722
1723 # Properties
1724 ( "-webkit-background-clip", "background-clip" ),
1725 ( "-webkit-background-origin", "background-origin" ),
1726 ( "-webkit-background-size", "background-size" ),
1727 ( "-webkit-box-shadow", "box-shadow" ),
1728
1729 # Functions
1730 ( "-webkit-gradient", "gradient" ),
1731 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1732 ( "-webkit-linear-gradient", "linear-gradient" ),
1733 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1734 ( "-webkit-radial-gradient", "radial-gradient" ),
1735 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1736]
1737
1738def _CheckNoDeprecatedCSS(input_api, output_api):
1739 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251740 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341741 documentation and iOS CSS for dom distiller
1742 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251743 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531744 results = []
dbeam070cfe62014-10-22 06:44:021745 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251746 black_list = (_EXCLUDED_PATHS +
1747 _TEST_CODE_EXCLUDED_PATHS +
1748 input_api.DEFAULT_BLACK_LIST +
1749 (r"^chrome/common/extensions/docs",
1750 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341751 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051752 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441753 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251754 r"^native_client_sdk"))
1755 file_filter = lambda f: input_api.FilterSourceFile(
1756 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531757 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1758 for line_num, line in fpath.ChangedContents():
1759 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021760 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531761 results.append(output_api.PresubmitError(
1762 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1763 (fpath.LocalPath(), line_num, deprecated_value, value)))
1764 return results
1765
mohan.reddyf21db962014-10-16 12:26:471766
dbeam070cfe62014-10-22 06:44:021767_DEPRECATED_JS = [
1768 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1769 ( "__defineGetter__", "Object.defineProperty" ),
1770 ( "__defineSetter__", "Object.defineProperty" ),
1771]
1772
1773def _CheckNoDeprecatedJS(input_api, output_api):
1774 """Make sure that we don't use deprecated JS in Chrome code."""
1775 results = []
1776 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1777 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1778 input_api.DEFAULT_BLACK_LIST)
1779 file_filter = lambda f: input_api.FilterSourceFile(
1780 f, white_list=file_inclusion_pattern, black_list=black_list)
1781 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1782 for lnum, line in fpath.ChangedContents():
1783 for (deprecated, replacement) in _DEPRECATED_JS:
1784 if deprecated in line:
1785 results.append(output_api.PresubmitError(
1786 "%s:%d: Use of deprecated JS %s, use %s instead" %
1787 (fpath.LocalPath(), lnum, deprecated, replacement)))
1788 return results
1789
1790
dgnaa68d5e2015-06-10 10:08:221791def _AndroidSpecificOnUploadChecks(input_api, output_api):
1792 """Groups checks that target android code."""
1793 results = []
dgnaa68d5e2015-06-10 10:08:221794 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221795 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291796 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221797 return results
1798
1799
[email protected]22c9bd72011-03-27 16:47:391800def _CommonChecks(input_api, output_api):
1801 """Checks common to both upload and commit."""
1802 results = []
1803 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381804 input_api, output_api,
1805 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461806 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191807 results.extend(
[email protected]760deea2013-12-10 19:33:491808 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541809 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181810 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521811 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221812 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441813 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591814 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061815 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121816 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181817 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221818 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491819 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271820 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031821 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491822 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441823 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271824 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541825 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441826 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391827 results.extend(_CheckFlakyTestUsage(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461828 # TODO(danakj): Remove this when base/move.h is removed.
dchengcf95c122015-12-18 08:29:161829 results.extend(_CheckForUsingPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551830 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041831 results.extend(
1832 input_api.canned_checks.CheckChangeHasNoTabs(
1833 input_api,
1834 output_api,
1835 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401836 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161837 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591838 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081839 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531840 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021841 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471842 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041843 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361844 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231845 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431846 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201847 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401848 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241849
1850 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1851 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1852 input_api, output_api,
1853 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381854 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391855 return results
[email protected]1f7b4172010-01-28 01:17:341856
[email protected]b337cb5b2011-01-23 21:24:051857
[email protected]66daa702011-05-28 14:41:461858def _CheckAuthorizedAuthor(input_api, output_api):
1859 """For non-googler/chromites committers, verify the author's email address is
1860 in AUTHORS.
1861 """
[email protected]9bb9cb82011-06-13 20:43:011862 # TODO(maruel): Add it to input_api?
1863 import fnmatch
1864
[email protected]66daa702011-05-28 14:41:461865 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011866 if not author:
1867 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461868 return []
[email protected]c99663292011-05-31 19:46:081869 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461870 input_api.PresubmitLocalPath(), 'AUTHORS')
1871 valid_authors = (
1872 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1873 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181874 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441875 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231876 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461877 return [output_api.PresubmitPromptWarning(
1878 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1879 '\n'
1880 'http://www.chromium.org/developers/contributing-code and read the '
1881 '"Legal" section\n'
1882 'If you are a chromite, verify the contributor signed the CLA.') %
1883 author)]
1884 return []
1885
1886
[email protected]b8079ae4a2012-12-05 19:56:491887def _CheckPatchFiles(input_api, output_api):
1888 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1889 if f.LocalPath().endswith(('.orig', '.rej'))]
1890 if problems:
1891 return [output_api.PresubmitError(
1892 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031893 else:
1894 return []
[email protected]b8079ae4a2012-12-05 19:56:491895
1896
[email protected]b00342e7f2013-03-26 16:21:541897def _DidYouMeanOSMacro(bad_macro):
1898 try:
1899 return {'A': 'OS_ANDROID',
1900 'B': 'OS_BSD',
1901 'C': 'OS_CHROMEOS',
1902 'F': 'OS_FREEBSD',
1903 'L': 'OS_LINUX',
1904 'M': 'OS_MACOSX',
1905 'N': 'OS_NACL',
1906 'O': 'OS_OPENBSD',
1907 'P': 'OS_POSIX',
1908 'S': 'OS_SOLARIS',
1909 'W': 'OS_WIN'}[bad_macro[3].upper()]
1910 except KeyError:
1911 return ''
1912
1913
1914def _CheckForInvalidOSMacrosInFile(input_api, f):
1915 """Check for sensible looking, totally invalid OS macros."""
1916 preprocessor_statement = input_api.re.compile(r'^\s*#')
1917 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1918 results = []
1919 for lnum, line in f.ChangedContents():
1920 if preprocessor_statement.search(line):
1921 for match in os_macro.finditer(line):
1922 if not match.group(1) in _VALID_OS_MACROS:
1923 good = _DidYouMeanOSMacro(match.group(1))
1924 did_you_mean = ' (did you mean %s?)' % good if good else ''
1925 results.append(' %s:%d %s%s' % (f.LocalPath(),
1926 lnum,
1927 match.group(1),
1928 did_you_mean))
1929 return results
1930
1931
1932def _CheckForInvalidOSMacros(input_api, output_api):
1933 """Check all affected files for invalid OS macros."""
1934 bad_macros = []
1935 for f in input_api.AffectedFiles():
1936 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1937 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1938
1939 if not bad_macros:
1940 return []
1941
1942 return [output_api.PresubmitError(
1943 'Possibly invalid OS macro[s] found. Please fix your code\n'
1944 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1945
lliabraa35bab3932014-10-01 12:16:441946
1947def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1948 """Check all affected files for invalid "if defined" macros."""
1949 ALWAYS_DEFINED_MACROS = (
1950 "TARGET_CPU_PPC",
1951 "TARGET_CPU_PPC64",
1952 "TARGET_CPU_68K",
1953 "TARGET_CPU_X86",
1954 "TARGET_CPU_ARM",
1955 "TARGET_CPU_MIPS",
1956 "TARGET_CPU_SPARC",
1957 "TARGET_CPU_ALPHA",
1958 "TARGET_IPHONE_SIMULATOR",
1959 "TARGET_OS_EMBEDDED",
1960 "TARGET_OS_IPHONE",
1961 "TARGET_OS_MAC",
1962 "TARGET_OS_UNIX",
1963 "TARGET_OS_WIN32",
1964 )
1965 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1966 results = []
1967 for lnum, line in f.ChangedContents():
1968 for match in ifdef_macro.finditer(line):
1969 if match.group(1) in ALWAYS_DEFINED_MACROS:
1970 always_defined = ' %s is always defined. ' % match.group(1)
1971 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1972 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1973 lnum,
1974 always_defined,
1975 did_you_mean))
1976 return results
1977
1978
1979def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1980 """Check all affected files for invalid "if defined" macros."""
1981 bad_macros = []
1982 for f in input_api.AffectedFiles():
1983 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1984 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1985
1986 if not bad_macros:
1987 return []
1988
1989 return [output_api.PresubmitError(
1990 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1991 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1992 bad_macros)]
1993
1994
dchengcf95c122015-12-18 08:29:161995def _CheckForUsingPass(input_api, output_api):
danakj3c84d0c2014-10-06 15:35:461996 """Check all affected files for using side effects of Pass."""
1997 errors = []
1998 for f in input_api.AffectedFiles():
1999 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2000 for lnum, line in f.ChangedContents():
dchengcf95c122015-12-18 08:29:162001 # Warn on any use of foo.Pass().
2002 if input_api.re.search(r'[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:462003 errors.append(output_api.PresubmitError(
dchengcf95c122015-12-18 08:29:162004 ('%s:%d uses Pass(); please use std::move() instead. ' +
2005 'See crbug.com/557422.') % (f.LocalPath(), lnum)))
danakj3c84d0c2014-10-06 15:35:462006 return errors
2007
2008
mlamouria82272622014-09-16 18:45:042009def _CheckForIPCRules(input_api, output_api):
2010 """Check for same IPC rules described in
2011 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2012 """
2013 base_pattern = r'IPC_ENUM_TRAITS\('
2014 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2015 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2016
2017 problems = []
2018 for f in input_api.AffectedSourceFiles(None):
2019 local_path = f.LocalPath()
2020 if not local_path.endswith('.h'):
2021 continue
2022 for line_number, line in f.ChangedContents():
2023 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2024 problems.append(
2025 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2026
2027 if problems:
2028 return [output_api.PresubmitPromptWarning(
2029 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2030 else:
2031 return []
2032
[email protected]b00342e7f2013-03-26 16:21:542033
mostynbb639aca52015-01-07 20:31:232034def _CheckForWindowsLineEndings(input_api, output_api):
2035 """Check source code and known ascii text files for Windows style line
2036 endings.
2037 """
earthdok1b5e0ee2015-03-10 15:19:102038 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232039
2040 file_inclusion_pattern = (
2041 known_text_files,
2042 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2043 )
2044
2045 filter = lambda f: input_api.FilterSourceFile(
2046 f, white_list=file_inclusion_pattern, black_list=None)
2047 files = [f.LocalPath() for f in
2048 input_api.AffectedSourceFiles(filter)]
2049
2050 problems = []
2051
2052 for file in files:
2053 fp = open(file, 'r')
2054 for line in fp:
2055 if line.endswith('\r\n'):
2056 problems.append(file)
2057 break
2058 fp.close()
2059
2060 if problems:
2061 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2062 'these files to contain Windows style line endings?\n' +
2063 '\n'.join(problems))]
2064
2065 return []
2066
2067
[email protected]1f7b4172010-01-28 01:17:342068def CheckChangeOnUpload(input_api, output_api):
2069 results = []
2070 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472071 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:172072 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:282073 results.extend(
2074 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192075 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222076 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542077 return results
[email protected]ca8d1982009-02-19 16:33:122078
2079
[email protected]1bfb8322014-04-23 01:02:412080def GetTryServerMasterForBot(bot):
2081 """Returns the Try Server master for the given bot.
2082
[email protected]0bb112362014-07-26 04:38:322083 It tries to guess the master from the bot name, but may still fail
2084 and return None. There is no longer a default master.
2085 """
2086 # Potentially ambiguous bot names are listed explicitly.
2087 master_map = {
[email protected]0bb112362014-07-26 04:38:322088 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322089 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412090 }
[email protected]0bb112362014-07-26 04:38:322091 master = master_map.get(bot)
2092 if not master:
sergiyb37fd293f2015-02-26 06:55:012093 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322094 master = 'tryserver.chromium.linux'
2095 elif 'win' in bot:
2096 master = 'tryserver.chromium.win'
2097 elif 'mac' in bot or 'ios' in bot:
2098 master = 'tryserver.chromium.mac'
2099 return master
[email protected]1bfb8322014-04-23 01:02:412100
2101
Paweł Hajdan, Jr55083782014-12-19 20:32:562102def GetDefaultTryConfigs(bots):
2103 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012104 """
2105
Paweł Hajdan, Jr55083782014-12-19 20:32:562106 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412107
2108 # Build up the mapping from tryserver master to bot/test.
2109 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562110 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412111 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2112 return out
[email protected]38c6a512013-12-18 23:48:012113
2114
[email protected]ca8d1982009-02-19 16:33:122115def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542116 results = []
[email protected]1f7b4172010-01-28 01:17:342117 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542118 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272119 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342120 input_api,
2121 output_api,
[email protected]2fdd1f362013-01-16 03:56:032122 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272123
[email protected]3e4eb112011-01-18 03:29:542124 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2125 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412126 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2127 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542128 return results