blob: 874734e4977c739df019f2d33496260820e4724d [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d19842009-02-19 16:33:1227
jochen9ea8fdbc2014-09-25 13:21:3528# The NetscapePlugIn library is excluded from pan-project as it will soon
29# be deleted together with the rest of the NPAPI and it's not worthwhile to
30# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3831_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3232 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3833)
34
[email protected]06e6d0ff2012-12-11 01:36:4435# Fragment of a regular expression that matches C++ and Objective-C++
36# implementation files.
37_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
38
39# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3244 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4450 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4951 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4752 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4953 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0854 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4955 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4456)
[email protected]ca8d19842009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
nyad2c548b2015-12-09 03:22:32167 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10168 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49169 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22170 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31171 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51172 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
173 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09174 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49175 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
176 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41177 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
178 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48179 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
180 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01181 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54182 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13183 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
184 "gnubby_auth_handler_linux\.cc$",
dnicoara171d8c82015-03-05 20:46:18185 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
rjkroege8471a0a92016-02-04 19:50:29186 "drm_display_host_manager\.cc$",
[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')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271057 if input_api.dry_run:
1058 return [output_api.PresubmitNotifyResult(
1059 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551060 if not input_api.change.issue:
1061 return [output_api.PresubmitError(
1062 "DEPS approval by OWNERS check failed: this change has "
1063 "no Rietveld issue number, so we can't check it for approvals.")]
1064 output = output_api.PresubmitError
1065 else:
1066 output = output_api.PresubmitNotifyResult
1067
1068 owners_db = input_api.owners_db
1069 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1070 input_api,
1071 owners_db.email_regexp,
1072 approval_needed=input_api.is_committing)
1073
1074 owner_email = owner_email or input_api.change.author_email
1075
[email protected]de4f7d22013-05-23 14:27:461076 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511077 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461078 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551079 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1080 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411081
1082 # We strip the /DEPS part that was added by
1083 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1084 # directory.
1085 def StripDeps(path):
1086 start_deps = path.rfind('/DEPS')
1087 if start_deps != -1:
1088 return path[:start_deps]
1089 else:
1090 return path
1091 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551092 for path in missing_files]
1093
1094 if unapproved_dependencies:
1095 output_list = [
[email protected]14a6131c2014-01-08 01:15:411096 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551097 '\n '.join(sorted(unapproved_dependencies)))]
1098 if not input_api.is_committing:
1099 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1100 output_list.append(output(
1101 'Suggested missing target path OWNERS:\n %s' %
1102 '\n '.join(suggested_owners or [])))
1103 return output_list
1104
1105 return []
1106
1107
[email protected]85218562013-11-22 07:41:401108def _CheckSpamLogging(input_api, output_api):
1109 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1110 black_list = (_EXCLUDED_PATHS +
1111 _TEST_CODE_EXCLUDED_PATHS +
1112 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501113 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191114 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481115 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461116 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121117 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1118 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581119 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161120 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031121 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151122 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1123 r"^chromecast[\\\/]",
1124 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311125 r"^components[\\\/]html_viewer[\\\/]"
1126 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461127 # TODO(peter): Remove this exception. https://crbug.com/534537
1128 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1129 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251130 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1131 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111132 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151133 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111134 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521135 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501136 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361137 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311138 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131139 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441140 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451141 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021142 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441143 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401144 source_file_filter = lambda x: input_api.FilterSourceFile(
1145 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1146
1147 log_info = []
1148 printf = []
1149
1150 for f in input_api.AffectedSourceFiles(source_file_filter):
1151 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471152 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401153 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471154 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131155 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371156
mohan.reddyf21db962014-10-16 12:26:471157 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371158 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471159 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401160 printf.append(f.LocalPath())
1161
1162 if log_info:
1163 return [output_api.PresubmitError(
1164 'These files spam the console log with LOG(INFO):',
1165 items=log_info)]
1166 if printf:
1167 return [output_api.PresubmitError(
1168 'These files spam the console log with printf/fprintf:',
1169 items=printf)]
1170 return []
1171
1172
[email protected]49aa76a2013-12-04 06:59:161173def _CheckForAnonymousVariables(input_api, output_api):
1174 """These types are all expected to hold locks while in scope and
1175 so should never be anonymous (which causes them to be immediately
1176 destroyed)."""
1177 they_who_must_be_named = [
1178 'base::AutoLock',
1179 'base::AutoReset',
1180 'base::AutoUnlock',
1181 'SkAutoAlphaRestore',
1182 'SkAutoBitmapShaderInstall',
1183 'SkAutoBlitterChoose',
1184 'SkAutoBounderCommit',
1185 'SkAutoCallProc',
1186 'SkAutoCanvasRestore',
1187 'SkAutoCommentBlock',
1188 'SkAutoDescriptor',
1189 'SkAutoDisableDirectionCheck',
1190 'SkAutoDisableOvalCheck',
1191 'SkAutoFree',
1192 'SkAutoGlyphCache',
1193 'SkAutoHDC',
1194 'SkAutoLockColors',
1195 'SkAutoLockPixels',
1196 'SkAutoMalloc',
1197 'SkAutoMaskFreeImage',
1198 'SkAutoMutexAcquire',
1199 'SkAutoPathBoundsUpdate',
1200 'SkAutoPDFRelease',
1201 'SkAutoRasterClipValidate',
1202 'SkAutoRef',
1203 'SkAutoTime',
1204 'SkAutoTrace',
1205 'SkAutoUnref',
1206 ]
1207 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1208 # bad: base::AutoLock(lock.get());
1209 # not bad: base::AutoLock lock(lock.get());
1210 bad_pattern = input_api.re.compile(anonymous)
1211 # good: new base::AutoLock(lock.get())
1212 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1213 errors = []
1214
1215 for f in input_api.AffectedFiles():
1216 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1217 continue
1218 for linenum, line in f.ChangedContents():
1219 if bad_pattern.search(line) and not good_pattern.search(line):
1220 errors.append('%s:%d' % (f.LocalPath(), linenum))
1221
1222 if errors:
1223 return [output_api.PresubmitError(
1224 'These lines create anonymous variables that need to be named:',
1225 items=errors)]
1226 return []
1227
1228
[email protected]5fe0f8742013-11-29 01:04:591229def _CheckCygwinShell(input_api, output_api):
1230 source_file_filter = lambda x: input_api.FilterSourceFile(
1231 x, white_list=(r'.+\.(gyp|gypi)$',))
1232 cygwin_shell = []
1233
1234 for f in input_api.AffectedSourceFiles(source_file_filter):
1235 for linenum, line in f.ChangedContents():
1236 if 'msvs_cygwin_shell' in line:
1237 cygwin_shell.append(f.LocalPath())
1238 break
1239
1240 if cygwin_shell:
1241 return [output_api.PresubmitError(
1242 'These files should not use msvs_cygwin_shell (the default is 0):',
1243 items=cygwin_shell)]
1244 return []
1245
[email protected]85218562013-11-22 07:41:401246
[email protected]999261d2014-03-03 20:08:081247def _CheckUserActionUpdate(input_api, output_api):
1248 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521249 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081250 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521251 # If actions.xml is already included in the changelist, the PRESUBMIT
1252 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081253 return []
1254
[email protected]999261d2014-03-03 20:08:081255 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1256 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521257 current_actions = None
[email protected]999261d2014-03-03 20:08:081258 for f in input_api.AffectedFiles(file_filter=file_filter):
1259 for line_num, line in f.ChangedContents():
1260 match = input_api.re.search(action_re, line)
1261 if match:
[email protected]2f92dec2014-03-07 19:21:521262 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1263 # loaded only once.
1264 if not current_actions:
1265 with open('tools/metrics/actions/actions.xml') as actions_f:
1266 current_actions = actions_f.read()
1267 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081268 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521269 action = 'name="{0}"'.format(action_name)
1270 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081271 return [output_api.PresubmitPromptWarning(
1272 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521273 'tools/metrics/actions/actions.xml. Please run '
1274 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081275 % (f.LocalPath(), line_num, action_name))]
1276 return []
1277
1278
[email protected]99171a92014-06-03 08:44:471279def _GetJSONParseError(input_api, filename, eat_comments=True):
1280 try:
1281 contents = input_api.ReadFile(filename)
1282 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131283 import sys
1284 original_sys_path = sys.path
1285 try:
1286 sys.path = sys.path + [input_api.os_path.join(
1287 input_api.PresubmitLocalPath(),
1288 'tools', 'json_comment_eater')]
1289 import json_comment_eater
1290 finally:
1291 sys.path = original_sys_path
1292 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471293
1294 input_api.json.loads(contents)
1295 except ValueError as e:
1296 return e
1297 return None
1298
1299
1300def _GetIDLParseError(input_api, filename):
1301 try:
1302 contents = input_api.ReadFile(filename)
1303 idl_schema = input_api.os_path.join(
1304 input_api.PresubmitLocalPath(),
1305 'tools', 'json_schema_compiler', 'idl_schema.py')
1306 process = input_api.subprocess.Popen(
1307 [input_api.python_executable, idl_schema],
1308 stdin=input_api.subprocess.PIPE,
1309 stdout=input_api.subprocess.PIPE,
1310 stderr=input_api.subprocess.PIPE,
1311 universal_newlines=True)
1312 (_, error) = process.communicate(input=contents)
1313 return error or None
1314 except ValueError as e:
1315 return e
1316
1317
1318def _CheckParseErrors(input_api, output_api):
1319 """Check that IDL and JSON files do not contain syntax errors."""
1320 actions = {
1321 '.idl': _GetIDLParseError,
1322 '.json': _GetJSONParseError,
1323 }
1324 # These paths contain test data and other known invalid JSON files.
1325 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491326 r'test[\\\/]data[\\\/]',
1327 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471328 ]
1329 # Most JSON files are preprocessed and support comments, but these do not.
1330 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491331 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471332 ]
1333 # Only run IDL checker on files in these directories.
1334 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491335 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1336 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471337 ]
1338
1339 def get_action(affected_file):
1340 filename = affected_file.LocalPath()
1341 return actions.get(input_api.os_path.splitext(filename)[1])
1342
1343 def MatchesFile(patterns, path):
1344 for pattern in patterns:
1345 if input_api.re.search(pattern, path):
1346 return True
1347 return False
1348
1349 def FilterFile(affected_file):
1350 action = get_action(affected_file)
1351 if not action:
1352 return False
1353 path = affected_file.LocalPath()
1354
1355 if MatchesFile(excluded_patterns, path):
1356 return False
1357
1358 if (action == _GetIDLParseError and
1359 not MatchesFile(idl_included_patterns, path)):
1360 return False
1361 return True
1362
1363 results = []
1364 for affected_file in input_api.AffectedFiles(
1365 file_filter=FilterFile, include_deletes=False):
1366 action = get_action(affected_file)
1367 kwargs = {}
1368 if (action == _GetJSONParseError and
1369 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1370 kwargs['eat_comments'] = False
1371 parse_error = action(input_api,
1372 affected_file.AbsoluteLocalPath(),
1373 **kwargs)
1374 if parse_error:
1375 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1376 (affected_file.LocalPath(), parse_error)))
1377 return results
1378
1379
[email protected]760deea2013-12-10 19:33:491380def _CheckJavaStyle(input_api, output_api):
1381 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471382 import sys
[email protected]760deea2013-12-10 19:33:491383 original_sys_path = sys.path
1384 try:
1385 sys.path = sys.path + [input_api.os_path.join(
1386 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1387 import checkstyle
1388 finally:
1389 # Restore sys.path to what it was before.
1390 sys.path = original_sys_path
1391
1392 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091393 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511394 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491395
1396
dskiba88634f4e2015-08-14 23:03:291397def _CheckAndroidToastUsage(input_api, output_api):
1398 """Checks that code uses org.chromium.ui.widget.Toast instead of
1399 android.widget.Toast (Chromium Toast doesn't force hardware
1400 acceleration on low-end devices, saving memory).
1401 """
1402 toast_import_pattern = input_api.re.compile(
1403 r'^import android\.widget\.Toast;$')
1404
1405 errors = []
1406
1407 sources = lambda affected_file: input_api.FilterSourceFile(
1408 affected_file,
1409 black_list=(_EXCLUDED_PATHS +
1410 _TEST_CODE_EXCLUDED_PATHS +
1411 input_api.DEFAULT_BLACK_LIST +
1412 (r'^chromecast[\\\/].*',
1413 r'^remoting[\\\/].*')),
1414 white_list=(r'.*\.java$',))
1415
1416 for f in input_api.AffectedSourceFiles(sources):
1417 for line_num, line in f.ChangedContents():
1418 if toast_import_pattern.search(line):
1419 errors.append("%s:%d" % (f.LocalPath(), line_num))
1420
1421 results = []
1422
1423 if errors:
1424 results.append(output_api.PresubmitError(
1425 'android.widget.Toast usage is detected. Android toasts use hardware'
1426 ' acceleration, and can be\ncostly on low-end devices. Please use'
1427 ' org.chromium.ui.widget.Toast instead.\n'
1428 'Contact [email protected] if you have any questions.',
1429 errors))
1430
1431 return results
1432
1433
dgnaa68d5e2015-06-10 10:08:221434def _CheckAndroidCrLogUsage(input_api, output_api):
1435 """Checks that new logs using org.chromium.base.Log:
1436 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511437 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221438 """
1439 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121440 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1441 class_in_base_pattern = input_api.re.compile(
1442 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1443 has_some_log_import_pattern = input_api.re.compile(
1444 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221445 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121446 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221447 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511448 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221449 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221450
Vincent Scheib16d7b272015-09-15 18:09:071451 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221452 'or contact [email protected] for more info.')
1453 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121454
dgnaa68d5e2015-06-10 10:08:221455 tag_decl_errors = []
1456 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121457 tag_errors = []
dgn38736db2015-09-18 19:20:511458 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121459 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221460
1461 for f in input_api.AffectedSourceFiles(sources):
1462 file_content = input_api.ReadFile(f)
1463 has_modified_logs = False
1464
1465 # Per line checks
dgn87d9fb62015-06-12 09:15:121466 if (cr_log_import_pattern.search(file_content) or
1467 (class_in_base_pattern.search(file_content) and
1468 not has_some_log_import_pattern.search(file_content))):
1469 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221470 for line_num, line in f.ChangedContents():
1471
1472 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121473 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221474 if match:
1475 has_modified_logs = True
1476
1477 # Make sure it uses "TAG"
1478 if not match.group('tag') == 'TAG':
1479 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121480 else:
1481 # Report non cr Log function calls in changed lines
1482 for line_num, line in f.ChangedContents():
1483 if log_call_pattern.search(line):
1484 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221485
1486 # Per file checks
1487 if has_modified_logs:
1488 # Make sure the tag is using the "cr" prefix and is not too long
1489 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511490 tag_name = match.group('name') if match else None
1491 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221492 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511493 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221494 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511495 elif '.' in tag_name:
1496 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221497
1498 results = []
1499 if tag_decl_errors:
1500 results.append(output_api.PresubmitPromptWarning(
1501 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511502 '"private static final String TAG = "<package tag>".\n'
1503 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221504 tag_decl_errors))
1505
1506 if tag_length_errors:
1507 results.append(output_api.PresubmitError(
1508 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511509 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221510 tag_length_errors))
1511
1512 if tag_errors:
1513 results.append(output_api.PresubmitPromptWarning(
1514 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1515 tag_errors))
1516
dgn87d9fb62015-06-12 09:15:121517 if util_log_errors:
dgn4401aa52015-04-29 16:26:171518 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121519 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1520 util_log_errors))
1521
dgn38736db2015-09-18 19:20:511522 if tag_with_dot_errors:
1523 results.append(output_api.PresubmitPromptWarning(
1524 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1525 tag_with_dot_errors))
1526
dgn4401aa52015-04-29 16:26:171527 return results
1528
1529
agrieve7b6479d82015-10-07 14:24:221530def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1531 """Checks if MDPI assets are placed in a correct directory."""
1532 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1533 ('/res/drawable/' in f.LocalPath() or
1534 '/res/drawable-ldrtl/' in f.LocalPath()))
1535 errors = []
1536 for f in input_api.AffectedFiles(include_deletes=False,
1537 file_filter=file_filter):
1538 errors.append(' %s' % f.LocalPath())
1539
1540 results = []
1541 if errors:
1542 results.append(output_api.PresubmitError(
1543 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1544 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1545 '/res/drawable-ldrtl/.\n'
1546 'Contact [email protected] if you have questions.', errors))
1547 return results
1548
1549
agrievef32bcc72016-04-04 14:57:401550class PydepsChecker(object):
1551 def __init__(self, input_api, pydeps_files):
1552 self._file_cache = {}
1553 self._input_api = input_api
1554 self._pydeps_files = pydeps_files
1555
1556 def _LoadFile(self, path):
1557 """Returns the list of paths within a .pydeps file relative to //."""
1558 if path not in self._file_cache:
1559 with open(path) as f:
1560 self._file_cache[path] = f.read()
1561 return self._file_cache[path]
1562
1563 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1564 """Returns an interable of paths within the .pydep, relativized to //."""
1565 os_path = self._input_api.os_path
1566 pydeps_dir = os_path.dirname(pydeps_path)
1567 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1568 if not l.startswith('*'))
1569 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1570
1571 def _CreateFilesToPydepsMap(self):
1572 """Returns a map of local_path -> list_of_pydeps."""
1573 ret = {}
1574 for pydep_local_path in self._pydeps_files:
1575 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1576 ret.setdefault(path, []).append(pydep_local_path)
1577 return ret
1578
1579 def ComputeAffectedPydeps(self):
1580 """Returns an iterable of .pydeps files that might need regenerating."""
1581 affected_pydeps = set()
1582 file_to_pydeps_map = None
1583 for f in self._input_api.AffectedFiles(include_deletes=True):
1584 local_path = f.LocalPath()
1585 if local_path == 'DEPS':
1586 return self._pydeps_files
1587 elif local_path.endswith('.pydeps'):
1588 if local_path in self._pydeps_files:
1589 affected_pydeps.add(local_path)
1590 elif local_path.endswith('.py'):
1591 if file_to_pydeps_map is None:
1592 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1593 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1594 return affected_pydeps
1595
1596 def DetermineIfStale(self, pydeps_path):
1597 """Runs print_python_deps.py to see if the files is stale."""
1598 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1599 cmd = old_pydeps_data[1][1:].strip()
1600 new_pydeps_data = self._input_api.subprocess.check_output(
1601 cmd + ' --output ""', shell=True)
1602 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1603 return cmd
1604
1605
1606def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1607 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001608 # This check is mainly for Android, and involves paths not only in the
1609 # PRESUBMIT.py, but also in the .pydeps files. Just skip it for Windows.
1610 if input_api.platform == 'win32':
1611 return []
agrievef32bcc72016-04-04 14:57:401612 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1613 is_android = input_api.os_path.exists('third_party/android_tools')
1614 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1615 results = []
1616 # First, check for new / deleted .pydeps.
1617 for f in input_api.AffectedFiles(include_deletes=True):
1618 if f.LocalPath().endswith('.pydeps'):
1619 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1620 results.append(output_api.PresubmitError(
1621 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1622 'remove %s' % f.LocalPath()))
1623 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1624 results.append(output_api.PresubmitError(
1625 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1626 'include %s' % f.LocalPath()))
1627
1628 if results:
1629 return results
1630
1631 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1632
1633 for pydep_path in checker.ComputeAffectedPydeps():
1634 try:
1635 cmd = checker.DetermineIfStale(pydep_path)
1636 if cmd:
1637 results.append(output_api.PresubmitError(
1638 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1639 (pydep_path, cmd)))
1640 except input_api.subprocess.CalledProcessError as error:
1641 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1642 long_text=error.output)]
1643
1644 return results
1645
1646
mnaganov9b9b1fe82014-12-11 16:30:361647def _CheckForCopyrightedCode(input_api, output_api):
1648 """Verifies that newly added code doesn't contain copyrighted material
1649 and is properly licensed under the standard Chromium license.
1650
1651 As there can be false positives, we maintain a whitelist file. This check
1652 also verifies that the whitelist file is up to date.
1653 """
1654 import sys
1655 original_sys_path = sys.path
1656 try:
1657 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221658 input_api.PresubmitLocalPath(), 'tools')]
1659 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361660 finally:
1661 # Restore sys.path to what it was before.
1662 sys.path = original_sys_path
1663
1664 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1665
1666
glidere61efad2015-02-18 17:39:431667def _CheckSingletonInHeaders(input_api, output_api):
1668 """Checks to make sure no header files have |Singleton<|."""
1669 def FileFilter(affected_file):
1670 # It's ok for base/memory/singleton.h to have |Singleton<|.
1671 black_list = (_EXCLUDED_PATHS +
1672 input_api.DEFAULT_BLACK_LIST +
1673 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1674 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1675
sergeyu34d21222015-09-16 00:11:441676 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431677 files = []
1678 for f in input_api.AffectedSourceFiles(FileFilter):
1679 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1680 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1681 contents = input_api.ReadFile(f)
1682 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241683 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431684 pattern.search(line)):
1685 files.append(f)
1686 break
1687
1688 if files:
yolandyandaabc6d2016-04-18 18:29:391689 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441690 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431691 'Please move them to an appropriate source file so that the ' +
1692 'template gets instantiated in a single compilation unit.',
1693 files) ]
1694 return []
1695
1696
dbeam37e8e7402016-02-10 22:58:201697def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1698 """Checks for old style compiled_resources.gyp files."""
1699 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1700
1701 added_compiled_resources = filter(is_compiled_resource, [
1702 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1703 ])
1704
1705 if not added_compiled_resources:
1706 return []
1707
1708 return [output_api.PresubmitError(
1709 "Found new compiled_resources.gyp files:\n%s\n\n"
1710 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551711 "please use compiled_resources2.gyp instead:\n"
1712 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1713 %
dbeam37e8e7402016-02-10 22:58:201714 "\n".join(added_compiled_resources))]
1715
1716
[email protected]fd20b902014-05-09 02:14:531717_DEPRECATED_CSS = [
1718 # Values
1719 ( "-webkit-box", "flex" ),
1720 ( "-webkit-inline-box", "inline-flex" ),
1721 ( "-webkit-flex", "flex" ),
1722 ( "-webkit-inline-flex", "inline-flex" ),
1723 ( "-webkit-min-content", "min-content" ),
1724 ( "-webkit-max-content", "max-content" ),
1725
1726 # Properties
1727 ( "-webkit-background-clip", "background-clip" ),
1728 ( "-webkit-background-origin", "background-origin" ),
1729 ( "-webkit-background-size", "background-size" ),
1730 ( "-webkit-box-shadow", "box-shadow" ),
1731
1732 # Functions
1733 ( "-webkit-gradient", "gradient" ),
1734 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1735 ( "-webkit-linear-gradient", "linear-gradient" ),
1736 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1737 ( "-webkit-radial-gradient", "radial-gradient" ),
1738 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1739]
1740
1741def _CheckNoDeprecatedCSS(input_api, output_api):
1742 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251743 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341744 documentation and iOS CSS for dom distiller
1745 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251746 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531747 results = []
dbeam070cfe62014-10-22 06:44:021748 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251749 black_list = (_EXCLUDED_PATHS +
1750 _TEST_CODE_EXCLUDED_PATHS +
1751 input_api.DEFAULT_BLACK_LIST +
1752 (r"^chrome/common/extensions/docs",
1753 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341754 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051755 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441756 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251757 r"^native_client_sdk"))
1758 file_filter = lambda f: input_api.FilterSourceFile(
1759 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531760 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1761 for line_num, line in fpath.ChangedContents():
1762 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021763 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531764 results.append(output_api.PresubmitError(
1765 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1766 (fpath.LocalPath(), line_num, deprecated_value, value)))
1767 return results
1768
mohan.reddyf21db962014-10-16 12:26:471769
dbeam070cfe62014-10-22 06:44:021770_DEPRECATED_JS = [
1771 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1772 ( "__defineGetter__", "Object.defineProperty" ),
1773 ( "__defineSetter__", "Object.defineProperty" ),
1774]
1775
1776def _CheckNoDeprecatedJS(input_api, output_api):
1777 """Make sure that we don't use deprecated JS in Chrome code."""
1778 results = []
1779 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1780 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1781 input_api.DEFAULT_BLACK_LIST)
1782 file_filter = lambda f: input_api.FilterSourceFile(
1783 f, white_list=file_inclusion_pattern, black_list=black_list)
1784 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1785 for lnum, line in fpath.ChangedContents():
1786 for (deprecated, replacement) in _DEPRECATED_JS:
1787 if deprecated in line:
1788 results.append(output_api.PresubmitError(
1789 "%s:%d: Use of deprecated JS %s, use %s instead" %
1790 (fpath.LocalPath(), lnum, deprecated, replacement)))
1791 return results
1792
1793
dgnaa68d5e2015-06-10 10:08:221794def _AndroidSpecificOnUploadChecks(input_api, output_api):
1795 """Groups checks that target android code."""
1796 results = []
dgnaa68d5e2015-06-10 10:08:221797 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221798 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291799 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221800 return results
1801
1802
[email protected]22c9bd72011-03-27 16:47:391803def _CommonChecks(input_api, output_api):
1804 """Checks common to both upload and commit."""
1805 results = []
1806 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381807 input_api, output_api,
1808 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461809 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191810 results.extend(
[email protected]760deea2013-12-10 19:33:491811 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541812 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181813 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521814 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221815 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441816 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591817 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061818 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121819 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181820 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221821 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491822 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271823 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031824 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491825 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441826 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271827 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541828 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441829 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391830 results.extend(_CheckFlakyTestUsage(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461831 # TODO(danakj): Remove this when base/move.h is removed.
dchengcf95c122015-12-18 08:29:161832 results.extend(_CheckForUsingPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551833 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041834 results.extend(
1835 input_api.canned_checks.CheckChangeHasNoTabs(
1836 input_api,
1837 output_api,
1838 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401839 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161840 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591841 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081842 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531843 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021844 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471845 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041846 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361847 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231848 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431849 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201850 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401851 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241852
1853 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1854 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1855 input_api, output_api,
1856 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381857 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391858 return results
[email protected]1f7b4172010-01-28 01:17:341859
[email protected]b337cb5b2011-01-23 21:24:051860
[email protected]66daa702011-05-28 14:41:461861def _CheckAuthorizedAuthor(input_api, output_api):
1862 """For non-googler/chromites committers, verify the author's email address is
1863 in AUTHORS.
1864 """
[email protected]9bb9cb82011-06-13 20:43:011865 # TODO(maruel): Add it to input_api?
1866 import fnmatch
1867
[email protected]66daa702011-05-28 14:41:461868 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011869 if not author:
1870 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461871 return []
[email protected]c99663292011-05-31 19:46:081872 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461873 input_api.PresubmitLocalPath(), 'AUTHORS')
1874 valid_authors = (
1875 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1876 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181877 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441878 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231879 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461880 return [output_api.PresubmitPromptWarning(
1881 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1882 '\n'
1883 'http://www.chromium.org/developers/contributing-code and read the '
1884 '"Legal" section\n'
1885 'If you are a chromite, verify the contributor signed the CLA.') %
1886 author)]
1887 return []
1888
1889
[email protected]b8079ae4a2012-12-05 19:56:491890def _CheckPatchFiles(input_api, output_api):
1891 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1892 if f.LocalPath().endswith(('.orig', '.rej'))]
1893 if problems:
1894 return [output_api.PresubmitError(
1895 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031896 else:
1897 return []
[email protected]b8079ae4a2012-12-05 19:56:491898
1899
[email protected]b00342e7f2013-03-26 16:21:541900def _DidYouMeanOSMacro(bad_macro):
1901 try:
1902 return {'A': 'OS_ANDROID',
1903 'B': 'OS_BSD',
1904 'C': 'OS_CHROMEOS',
1905 'F': 'OS_FREEBSD',
1906 'L': 'OS_LINUX',
1907 'M': 'OS_MACOSX',
1908 'N': 'OS_NACL',
1909 'O': 'OS_OPENBSD',
1910 'P': 'OS_POSIX',
1911 'S': 'OS_SOLARIS',
1912 'W': 'OS_WIN'}[bad_macro[3].upper()]
1913 except KeyError:
1914 return ''
1915
1916
1917def _CheckForInvalidOSMacrosInFile(input_api, f):
1918 """Check for sensible looking, totally invalid OS macros."""
1919 preprocessor_statement = input_api.re.compile(r'^\s*#')
1920 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1921 results = []
1922 for lnum, line in f.ChangedContents():
1923 if preprocessor_statement.search(line):
1924 for match in os_macro.finditer(line):
1925 if not match.group(1) in _VALID_OS_MACROS:
1926 good = _DidYouMeanOSMacro(match.group(1))
1927 did_you_mean = ' (did you mean %s?)' % good if good else ''
1928 results.append(' %s:%d %s%s' % (f.LocalPath(),
1929 lnum,
1930 match.group(1),
1931 did_you_mean))
1932 return results
1933
1934
1935def _CheckForInvalidOSMacros(input_api, output_api):
1936 """Check all affected files for invalid OS macros."""
1937 bad_macros = []
1938 for f in input_api.AffectedFiles():
1939 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1940 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1941
1942 if not bad_macros:
1943 return []
1944
1945 return [output_api.PresubmitError(
1946 'Possibly invalid OS macro[s] found. Please fix your code\n'
1947 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1948
lliabraa35bab3932014-10-01 12:16:441949
1950def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1951 """Check all affected files for invalid "if defined" macros."""
1952 ALWAYS_DEFINED_MACROS = (
1953 "TARGET_CPU_PPC",
1954 "TARGET_CPU_PPC64",
1955 "TARGET_CPU_68K",
1956 "TARGET_CPU_X86",
1957 "TARGET_CPU_ARM",
1958 "TARGET_CPU_MIPS",
1959 "TARGET_CPU_SPARC",
1960 "TARGET_CPU_ALPHA",
1961 "TARGET_IPHONE_SIMULATOR",
1962 "TARGET_OS_EMBEDDED",
1963 "TARGET_OS_IPHONE",
1964 "TARGET_OS_MAC",
1965 "TARGET_OS_UNIX",
1966 "TARGET_OS_WIN32",
1967 )
1968 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1969 results = []
1970 for lnum, line in f.ChangedContents():
1971 for match in ifdef_macro.finditer(line):
1972 if match.group(1) in ALWAYS_DEFINED_MACROS:
1973 always_defined = ' %s is always defined. ' % match.group(1)
1974 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1975 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1976 lnum,
1977 always_defined,
1978 did_you_mean))
1979 return results
1980
1981
1982def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1983 """Check all affected files for invalid "if defined" macros."""
1984 bad_macros = []
1985 for f in input_api.AffectedFiles():
1986 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1987 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1988
1989 if not bad_macros:
1990 return []
1991
1992 return [output_api.PresubmitError(
1993 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1994 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1995 bad_macros)]
1996
1997
dchengcf95c122015-12-18 08:29:161998def _CheckForUsingPass(input_api, output_api):
danakj3c84d0c2014-10-06 15:35:461999 """Check all affected files for using side effects of Pass."""
2000 errors = []
2001 for f in input_api.AffectedFiles():
2002 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2003 for lnum, line in f.ChangedContents():
dchengcf95c122015-12-18 08:29:162004 # Warn on any use of foo.Pass().
2005 if input_api.re.search(r'[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:462006 errors.append(output_api.PresubmitError(
dchengcf95c122015-12-18 08:29:162007 ('%s:%d uses Pass(); please use std::move() instead. ' +
2008 'See crbug.com/557422.') % (f.LocalPath(), lnum)))
danakj3c84d0c2014-10-06 15:35:462009 return errors
2010
2011
mlamouria82272622014-09-16 18:45:042012def _CheckForIPCRules(input_api, output_api):
2013 """Check for same IPC rules described in
2014 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2015 """
2016 base_pattern = r'IPC_ENUM_TRAITS\('
2017 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2018 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2019
2020 problems = []
2021 for f in input_api.AffectedSourceFiles(None):
2022 local_path = f.LocalPath()
2023 if not local_path.endswith('.h'):
2024 continue
2025 for line_number, line in f.ChangedContents():
2026 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2027 problems.append(
2028 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2029
2030 if problems:
2031 return [output_api.PresubmitPromptWarning(
2032 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2033 else:
2034 return []
2035
[email protected]b00342e7f2013-03-26 16:21:542036
mostynbb639aca52015-01-07 20:31:232037def _CheckForWindowsLineEndings(input_api, output_api):
2038 """Check source code and known ascii text files for Windows style line
2039 endings.
2040 """
earthdok1b5e0ee2015-03-10 15:19:102041 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232042
2043 file_inclusion_pattern = (
2044 known_text_files,
2045 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2046 )
2047
2048 filter = lambda f: input_api.FilterSourceFile(
2049 f, white_list=file_inclusion_pattern, black_list=None)
2050 files = [f.LocalPath() for f in
2051 input_api.AffectedSourceFiles(filter)]
2052
2053 problems = []
2054
2055 for file in files:
2056 fp = open(file, 'r')
2057 for line in fp:
2058 if line.endswith('\r\n'):
2059 problems.append(file)
2060 break
2061 fp.close()
2062
2063 if problems:
2064 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2065 'these files to contain Windows style line endings?\n' +
2066 '\n'.join(problems))]
2067
2068 return []
2069
2070
[email protected]1f7b4172010-01-28 01:17:342071def CheckChangeOnUpload(input_api, output_api):
2072 results = []
2073 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472074 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:172075 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:282076 results.extend(
2077 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192078 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222079 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542080 return results
[email protected]ca8d19842009-02-19 16:33:122081
2082
[email protected]1bfb8322014-04-23 01:02:412083def GetTryServerMasterForBot(bot):
2084 """Returns the Try Server master for the given bot.
2085
[email protected]0bb112362014-07-26 04:38:322086 It tries to guess the master from the bot name, but may still fail
2087 and return None. There is no longer a default master.
2088 """
2089 # Potentially ambiguous bot names are listed explicitly.
2090 master_map = {
[email protected]0bb112362014-07-26 04:38:322091 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322092 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412093 }
[email protected]0bb112362014-07-26 04:38:322094 master = master_map.get(bot)
2095 if not master:
sergiyb37fd293f2015-02-26 06:55:012096 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322097 master = 'tryserver.chromium.linux'
2098 elif 'win' in bot:
2099 master = 'tryserver.chromium.win'
2100 elif 'mac' in bot or 'ios' in bot:
2101 master = 'tryserver.chromium.mac'
2102 return master
[email protected]1bfb8322014-04-23 01:02:412103
2104
Paweł Hajdan, Jr55083782014-12-19 20:32:562105def GetDefaultTryConfigs(bots):
2106 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012107 """
2108
Paweł Hajdan, Jr55083782014-12-19 20:32:562109 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412110
2111 # Build up the mapping from tryserver master to bot/test.
2112 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562113 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412114 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2115 return out
[email protected]38c6a512013-12-18 23:48:012116
2117
[email protected]ca8d19842009-02-19 16:33:122118def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542119 results = []
[email protected]1f7b4172010-01-28 01:17:342120 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542121 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272122 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342123 input_api,
2124 output_api,
[email protected]2fdd1f362013-01-16 03:56:032125 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272126
[email protected]3e4eb112011-01-18 03:29:542127 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2128 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412129 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2130 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542131 return results