blob: 4421f2ed740039d89fe6465ef67e340e6e6aa49c [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d1982009-02-19 16:33:1227
jochen9ea8fdbc2014-09-25 13:21:3528# The NetscapePlugIn library is excluded from pan-project as it will soon
29# be deleted together with the rest of the NPAPI and it's not worthwhile to
30# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3831_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3232 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3833)
34
[email protected]06e6d0ff2012-12-11 01:36:4435# Fragment of a regular expression that matches C++ and Objective-C++
36# implementation files.
37_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
38
39# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3244 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4450 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4951 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4752 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4953 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0854 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4955 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4456)
[email protected]ca8d1982009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
nyad2c548b2015-12-09 03:22:32167 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10168 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49169 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22170 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31171 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51172 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
173 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09174 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49175 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
176 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41177 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
178 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48179 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
180 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01181 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54182 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13183 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
184 "gnubby_auth_handler_linux\.cc$",
dnicoara171d8c82015-03-05 20:46:18185 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
rjkroege8471a0a92016-02-04 19:50:29186 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49187 ),
[email protected]23e6cbc2012-06-16 18:51:20188 ),
[email protected]52657f62013-05-20 05:30:31189 (
tomhudson7e6e0512016-04-19 19:27:22190 'skia::RefPtr',
191 (
192 'The use of skia::RefPtr is prohibited. ',
193 'Please use sk_sp<> instead.'
194 ),
195 True,
196 (),
197 ),
198 (
[email protected]52657f62013-05-20 05:30:31199 'SkRefPtr',
200 (
201 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22202 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31203 ),
204 True,
205 (),
206 ),
207 (
208 'SkAutoRef',
209 (
210 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22211 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31212 ),
213 True,
214 (),
215 ),
216 (
217 'SkAutoTUnref',
218 (
219 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22220 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31221 ),
222 True,
223 (),
224 ),
225 (
226 'SkAutoUnref',
227 (
228 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
229 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22230 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31231 ),
232 True,
233 (),
234 ),
[email protected]d89eec82013-12-03 14:10:59235 (
236 r'/HANDLE_EINTR\(.*close',
237 (
238 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
239 'descriptor will be closed, and it is incorrect to retry the close.',
240 'Either call close directly and ignore its return value, or wrap close',
241 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
242 ),
243 True,
244 (),
245 ),
246 (
247 r'/IGNORE_EINTR\((?!.*close)',
248 (
249 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
250 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
251 ),
252 True,
253 (
254 # Files that #define IGNORE_EINTR.
255 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
256 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
257 ),
258 ),
[email protected]ec5b3f02014-04-04 18:43:43259 (
260 r'/v8::Extension\(',
261 (
262 'Do not introduce new v8::Extensions into the code base, use',
263 'gin::Wrappable instead. See http://crbug.com/334679',
264 ),
265 True,
[email protected]f55c90ee62014-04-12 00:50:03266 (
joaodasilva718f87672014-08-30 09:25:49267 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03268 ),
[email protected]ec5b3f02014-04-04 18:43:43269 ),
skyostilf9469f72015-04-20 10:38:52270 (
sdefresneeaeccc52015-04-22 08:18:32271 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52272 (
273 'MessageLoopProxy is deprecated. ',
274 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
275 ),
276 True,
kinuko59024ce2015-04-21 22:18:30277 (
278 # Internal message_loop related code may still use it.
279 r'^base[\\\/]message_loop[\\\/].*',
280 ),
skyostilf9469f72015-04-20 10:38:52281 ),
jame2d1a952016-04-02 00:27:10282 (
283 '#pragma comment(lib,',
284 (
285 'Specify libraries to link with in build files and not in the source.',
286 ),
287 True,
288 (),
289 ),
[email protected]127f18ec2012-06-16 05:05:59290)
291
mlamouria82272622014-09-16 18:45:04292_IPC_ENUM_TRAITS_DEPRECATED = (
293 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
294 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
295
[email protected]127f18ec2012-06-16 05:05:59296
[email protected]b00342e7f2013-03-26 16:21:54297_VALID_OS_MACROS = (
298 # Please keep sorted.
299 'OS_ANDROID',
300 'OS_BSD',
301 'OS_CAT', # For testing.
302 'OS_CHROMEOS',
303 'OS_FREEBSD',
304 'OS_IOS',
305 'OS_LINUX',
306 'OS_MACOSX',
307 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21308 'OS_NACL_NONSFI',
309 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54310 'OS_OPENBSD',
311 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37312 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54313 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54314 'OS_WIN',
315)
316
317
agrievef32bcc72016-04-04 14:57:40318_ANDROID_SPECIFIC_PYDEPS_FILES = [
319 'build/android/test_runner.pydeps',
320]
321
322_GENERIC_PYDEPS_FILES = [
323 'build/secondary/tools/swarming_client/isolate.pydeps',
324]
325
326_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
327
328
[email protected]55459852011-08-10 15:17:19329def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
330 """Attempts to prevent use of functions intended only for testing in
331 non-testing code. For now this is just a best-effort implementation
332 that ignores header files and may have some false positives. A
333 better implementation would probably need a proper C++ parser.
334 """
335 # We only scan .cc files and the like, as the declaration of
336 # for-testing functions in header files are hard to distinguish from
337 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44338 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19339
jochenc0d4808c2015-07-27 09:25:42340 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19341 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09342 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19343 exclusion_pattern = input_api.re.compile(
344 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
345 base_function_pattern, base_function_pattern))
346
347 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44348 black_list = (_EXCLUDED_PATHS +
349 _TEST_CODE_EXCLUDED_PATHS +
350 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19351 return input_api.FilterSourceFile(
352 affected_file,
353 white_list=(file_inclusion_pattern, ),
354 black_list=black_list)
355
356 problems = []
357 for f in input_api.AffectedSourceFiles(FilterFile):
358 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24359 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03360 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46361 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03362 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19363 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03364 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19365
366 if problems:
[email protected]f7051d52013-04-02 18:31:42367 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03368 else:
369 return []
[email protected]55459852011-08-10 15:17:19370
371
[email protected]10689ca2011-09-02 02:31:54372def _CheckNoIOStreamInHeaders(input_api, output_api):
373 """Checks to make sure no .h files include <iostream>."""
374 files = []
375 pattern = input_api.re.compile(r'^#include\s*<iostream>',
376 input_api.re.MULTILINE)
377 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
378 if not f.LocalPath().endswith('.h'):
379 continue
380 contents = input_api.ReadFile(f)
381 if pattern.search(contents):
382 files.append(f)
383
384 if len(files):
yolandyandaabc6d2016-04-18 18:29:39385 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06386 'Do not #include <iostream> in header files, since it inserts static '
387 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54388 '#include <ostream>. See http://crbug.com/94794',
389 files) ]
390 return []
391
392
[email protected]72df4e782012-06-21 16:28:18393def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52394 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18395 problems = []
396 for f in input_api.AffectedFiles():
397 if (not f.LocalPath().endswith(('.cc', '.mm'))):
398 continue
399
400 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04401 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18402 problems.append(' %s:%d' % (f.LocalPath(), line_num))
403
404 if not problems:
405 return []
406 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
407 '\n'.join(problems))]
408
409
danakj61c1aa22015-10-26 19:55:52410def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
411 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
412 errors = []
413 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
414 input_api.re.MULTILINE)
415 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
416 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
417 continue
418 for lnum, line in f.ChangedContents():
419 if input_api.re.search(pattern, line):
420 errors.append(output_api.PresubmitError(
421 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
422 'DCHECK_IS_ON()", not forgetting the braces.')
423 % (f.LocalPath(), lnum)))
424 return errors
425
426
mcasasb7440c282015-02-04 14:52:19427def _FindHistogramNameInLine(histogram_name, line):
428 """Tries to find a histogram name or prefix in a line."""
429 if not "affected-histogram" in line:
430 return histogram_name in line
431 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
432 # the histogram_name.
433 if not '"' in line:
434 return False
435 histogram_prefix = line.split('\"')[1]
436 return histogram_prefix in histogram_name
437
438
439def _CheckUmaHistogramChanges(input_api, output_api):
440 """Check that UMA histogram names in touched lines can still be found in other
441 lines of the patch or in histograms.xml. Note that this check would not catch
442 the reverse: changes in histograms.xml not matched in the code itself."""
443 touched_histograms = []
444 histograms_xml_modifications = []
445 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
446 for f in input_api.AffectedFiles():
447 # If histograms.xml itself is modified, keep the modified lines for later.
448 if f.LocalPath().endswith(('histograms.xml')):
449 histograms_xml_modifications = f.ChangedContents()
450 continue
451 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
452 continue
453 for line_num, line in f.ChangedContents():
454 found = pattern.search(line)
455 if found:
456 touched_histograms.append([found.group(1), f, line_num])
457
458 # Search for the touched histogram names in the local modifications to
459 # histograms.xml, and, if not found, on the base histograms.xml file.
460 unmatched_histograms = []
461 for histogram_info in touched_histograms:
462 histogram_name_found = False
463 for line_num, line in histograms_xml_modifications:
464 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
465 if histogram_name_found:
466 break
467 if not histogram_name_found:
468 unmatched_histograms.append(histogram_info)
469
eromanb90c82e7e32015-04-01 15:13:49470 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19471 problems = []
472 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49473 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19474 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45475 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19476 histogram_name_found = False
477 for line in histograms_xml:
478 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
479 if histogram_name_found:
480 break
481 if not histogram_name_found:
482 problems.append(' [%s:%d] %s' %
483 (f.LocalPath(), line_num, histogram_name))
484
485 if not problems:
486 return []
487 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
488 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49489 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19490
yolandyandaabc6d2016-04-18 18:29:39491def _CheckFlakyTestUsage(input_api, output_api):
492 """Check that FlakyTest annotation is our own instead of the android one"""
493 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
494 files = []
495 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
496 if f.LocalPath().endswith('Test.java'):
497 if pattern.search(input_api.ReadFile(f)):
498 files.append(f)
499 if len(files):
500 return [output_api.PresubmitError(
501 'Use org.chromium.base.test.util.FlakyTest instead of '
502 'android.test.FlakyTest',
503 files)]
504 return []
mcasasb7440c282015-02-04 14:52:19505
[email protected]8ea5d4b2011-09-13 21:49:22506def _CheckNoNewWStrings(input_api, output_api):
507 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27508 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22509 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20510 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57511 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
512 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20513 continue
[email protected]8ea5d4b2011-09-13 21:49:22514
[email protected]a11dbe9b2012-08-07 01:32:58515 allowWString = False
[email protected]b5c24292011-11-28 14:38:20516 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58517 if 'presubmit: allow wstring' in line:
518 allowWString = True
519 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27520 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58521 allowWString = False
522 else:
523 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22524
[email protected]55463aa62011-10-12 00:48:27525 if not problems:
526 return []
527 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58528 ' If you are calling a cross-platform API that accepts a wstring, '
529 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27530 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22531
532
[email protected]2a8ac9c2011-10-19 17:20:44533def _CheckNoDEPSGIT(input_api, output_api):
534 """Make sure .DEPS.git is never modified manually."""
535 if any(f.LocalPath().endswith('.DEPS.git') for f in
536 input_api.AffectedFiles()):
537 return [output_api.PresubmitError(
538 'Never commit changes to .DEPS.git. This file is maintained by an\n'
539 'automated system based on what\'s in DEPS and your changes will be\n'
540 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34541 '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:44542 'for more information')]
543 return []
544
545
tandriief664692014-09-23 14:51:47546def _CheckValidHostsInDEPS(input_api, output_api):
547 """Checks that DEPS file deps are from allowed_hosts."""
548 # Run only if DEPS file has been modified to annoy fewer bystanders.
549 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
550 return []
551 # Outsource work to gclient verify
552 try:
553 input_api.subprocess.check_output(['gclient', 'verify'])
554 return []
555 except input_api.subprocess.CalledProcessError, error:
556 return [output_api.PresubmitError(
557 'DEPS file must have only git dependencies.',
558 long_text=error.output)]
559
560
[email protected]127f18ec2012-06-16 05:05:59561def _CheckNoBannedFunctions(input_api, output_api):
562 """Make sure that banned functions are not used."""
563 warnings = []
564 errors = []
565
566 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
567 for f in input_api.AffectedFiles(file_filter=file_filter):
568 for line_num, line in f.ChangedContents():
569 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26570 matched = False
571 if func_name[0:1] == '/':
572 regex = func_name[1:]
573 if input_api.re.search(regex, line):
574 matched = True
575 elif func_name in line:
576 matched = True
577 if matched:
[email protected]127f18ec2012-06-16 05:05:59578 problems = warnings;
579 if error:
580 problems = errors;
581 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
582 for message_line in message:
583 problems.append(' %s' % message_line)
584
585 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
586 for f in input_api.AffectedFiles(file_filter=file_filter):
587 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49588 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
589 def IsBlacklisted(affected_file, blacklist):
590 local_path = affected_file.LocalPath()
591 for item in blacklist:
592 if input_api.re.match(item, local_path):
593 return True
594 return False
595 if IsBlacklisted(f, excluded_paths):
596 continue
[email protected]d89eec82013-12-03 14:10:59597 matched = False
598 if func_name[0:1] == '/':
599 regex = func_name[1:]
600 if input_api.re.search(regex, line):
601 matched = True
602 elif func_name in line:
603 matched = True
604 if matched:
[email protected]127f18ec2012-06-16 05:05:59605 problems = warnings;
606 if error:
607 problems = errors;
608 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
609 for message_line in message:
610 problems.append(' %s' % message_line)
611
612 result = []
613 if (warnings):
614 result.append(output_api.PresubmitPromptWarning(
615 'Banned functions were used.\n' + '\n'.join(warnings)))
616 if (errors):
617 result.append(output_api.PresubmitError(
618 'Banned functions were used.\n' + '\n'.join(errors)))
619 return result
620
621
[email protected]6c063c62012-07-11 19:11:06622def _CheckNoPragmaOnce(input_api, output_api):
623 """Make sure that banned functions are not used."""
624 files = []
625 pattern = input_api.re.compile(r'^#pragma\s+once',
626 input_api.re.MULTILINE)
627 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
628 if not f.LocalPath().endswith('.h'):
629 continue
630 contents = input_api.ReadFile(f)
631 if pattern.search(contents):
632 files.append(f)
633
634 if files:
635 return [output_api.PresubmitError(
636 'Do not use #pragma once in header files.\n'
637 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
638 files)]
639 return []
640
[email protected]127f18ec2012-06-16 05:05:59641
[email protected]e7479052012-09-19 00:26:12642def _CheckNoTrinaryTrueFalse(input_api, output_api):
643 """Checks to make sure we don't introduce use of foo ? true : false."""
644 problems = []
645 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
646 for f in input_api.AffectedFiles():
647 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
648 continue
649
650 for line_num, line in f.ChangedContents():
651 if pattern.match(line):
652 problems.append(' %s:%d' % (f.LocalPath(), line_num))
653
654 if not problems:
655 return []
656 return [output_api.PresubmitPromptWarning(
657 'Please consider avoiding the "? true : false" pattern if possible.\n' +
658 '\n'.join(problems))]
659
660
[email protected]55f9f382012-07-31 11:02:18661def _CheckUnwantedDependencies(input_api, output_api):
662 """Runs checkdeps on #include statements added in this
663 change. Breaking - rules is an error, breaking ! rules is a
664 warning.
665 """
mohan.reddyf21db962014-10-16 12:26:47666 import sys
[email protected]55f9f382012-07-31 11:02:18667 # We need to wait until we have an input_api object and use this
668 # roundabout construct to import checkdeps because this file is
669 # eval-ed and thus doesn't have __file__.
670 original_sys_path = sys.path
671 try:
672 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47673 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18674 import checkdeps
675 from cpp_checker import CppChecker
676 from rules import Rule
677 finally:
678 # Restore sys.path to what it was before.
679 sys.path = original_sys_path
680
681 added_includes = []
682 for f in input_api.AffectedFiles():
683 if not CppChecker.IsCppFile(f.LocalPath()):
684 continue
685
686 changed_lines = [line for line_num, line in f.ChangedContents()]
687 added_includes.append([f.LocalPath(), changed_lines])
688
[email protected]26385172013-05-09 23:11:35689 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18690
691 error_descriptions = []
692 warning_descriptions = []
693 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
694 added_includes):
695 description_with_path = '%s\n %s' % (path, rule_description)
696 if rule_type == Rule.DISALLOW:
697 error_descriptions.append(description_with_path)
698 else:
699 warning_descriptions.append(description_with_path)
700
701 results = []
702 if error_descriptions:
703 results.append(output_api.PresubmitError(
704 'You added one or more #includes that violate checkdeps rules.',
705 error_descriptions))
706 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42707 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18708 'You added one or more #includes of files that are temporarily\n'
709 'allowed but being removed. Can you avoid introducing the\n'
710 '#include? See relevant DEPS file(s) for details and contacts.',
711 warning_descriptions))
712 return results
713
714
[email protected]fbcafe5a2012-08-08 15:31:22715def _CheckFilePermissions(input_api, output_api):
716 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15717 if input_api.platform == 'win32':
718 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29719 checkperms_tool = input_api.os_path.join(
720 input_api.PresubmitLocalPath(),
721 'tools', 'checkperms', 'checkperms.py')
722 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47723 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22724 for f in input_api.AffectedFiles():
725 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11726 try:
727 input_api.subprocess.check_output(args)
728 return []
729 except input_api.subprocess.CalledProcessError as error:
730 return [output_api.PresubmitError(
731 'checkperms.py failed:',
732 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22733
734
[email protected]c8278b32012-10-30 20:35:49735def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
736 """Makes sure we don't include ui/aura/window_property.h
737 in header files.
738 """
739 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
740 errors = []
741 for f in input_api.AffectedFiles():
742 if not f.LocalPath().endswith('.h'):
743 continue
744 for line_num, line in f.ChangedContents():
745 if pattern.match(line):
746 errors.append(' %s:%d' % (f.LocalPath(), line_num))
747
748 results = []
749 if errors:
750 results.append(output_api.PresubmitError(
751 'Header files should not include ui/aura/window_property.h', errors))
752 return results
753
754
[email protected]cf9b78f2012-11-14 11:40:28755def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
756 """Checks that the lines in scope occur in the right order.
757
758 1. C system files in alphabetical order
759 2. C++ system files in alphabetical order
760 3. Project's .h files
761 """
762
763 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
764 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
765 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
766
767 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
768
769 state = C_SYSTEM_INCLUDES
770
771 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57772 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28773 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55774 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28775 for line_num, line in scope:
776 if c_system_include_pattern.match(line):
777 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55778 problem_linenums.append((line_num, previous_line_num,
779 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28780 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55781 problem_linenums.append((line_num, previous_line_num,
782 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28783 elif cpp_system_include_pattern.match(line):
784 if state == C_SYSTEM_INCLUDES:
785 state = CPP_SYSTEM_INCLUDES
786 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55787 problem_linenums.append((line_num, previous_line_num,
788 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28789 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55790 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28791 elif custom_include_pattern.match(line):
792 if state != CUSTOM_INCLUDES:
793 state = CUSTOM_INCLUDES
794 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55795 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28796 else:
brucedawson70fadb02015-06-30 17:47:55797 problem_linenums.append((line_num, previous_line_num,
798 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28799 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57800 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28801
802 warnings = []
brucedawson70fadb02015-06-30 17:47:55803 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57804 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55805 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28806 return warnings
807
808
[email protected]ac294a12012-12-06 16:38:43809def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28810 """Checks the #include order for the given file f."""
811
[email protected]2299dcf2012-11-15 19:56:24812 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30813 # Exclude the following includes from the check:
814 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
815 # specific order.
816 # 2) <atlbase.h>, "build/build_config.h"
817 excluded_include_pattern = input_api.re.compile(
818 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24819 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33820 # Match the final or penultimate token if it is xxxtest so we can ignore it
821 # when considering the special first include.
822 test_file_tag_pattern = input_api.re.compile(
823 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11824 if_pattern = input_api.re.compile(
825 r'\s*#\s*(if|elif|else|endif|define|undef).*')
826 # Some files need specialized order of includes; exclude such files from this
827 # check.
828 uncheckable_includes_pattern = input_api.re.compile(
829 r'\s*#include '
830 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28831
832 contents = f.NewContents()
833 warnings = []
834 line_num = 0
835
[email protected]ac294a12012-12-06 16:38:43836 # Handle the special first include. If the first include file is
837 # some/path/file.h, the corresponding including file can be some/path/file.cc,
838 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
839 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33840 # If the included file is some/path/file_platform.h the including file could
841 # also be some/path/file_xxxtest_platform.h.
842 including_file_base_name = test_file_tag_pattern.sub(
843 '', input_api.os_path.basename(f.LocalPath()))
844
[email protected]ac294a12012-12-06 16:38:43845 for line in contents:
846 line_num += 1
847 if system_include_pattern.match(line):
848 # No special first include -> process the line again along with normal
849 # includes.
850 line_num -= 1
851 break
852 match = custom_include_pattern.match(line)
853 if match:
854 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33855 header_basename = test_file_tag_pattern.sub(
856 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
857
858 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24859 # No special first include -> process the line again along with normal
860 # includes.
861 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43862 break
[email protected]cf9b78f2012-11-14 11:40:28863
864 # Split into scopes: Each region between #if and #endif is its own scope.
865 scopes = []
866 current_scope = []
867 for line in contents[line_num:]:
868 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11869 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54870 continue
[email protected]2309b0fa02012-11-16 12:18:27871 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28872 scopes.append(current_scope)
873 current_scope = []
[email protected]962f117e2012-11-22 18:11:56874 elif ((system_include_pattern.match(line) or
875 custom_include_pattern.match(line)) and
876 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28877 current_scope.append((line_num, line))
878 scopes.append(current_scope)
879
880 for scope in scopes:
881 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
882 changed_linenums))
883 return warnings
884
885
886def _CheckIncludeOrder(input_api, output_api):
887 """Checks that the #include order is correct.
888
889 1. The corresponding header for source files.
890 2. C system files in alphabetical order
891 3. C++ system files in alphabetical order
892 4. Project's .h files in alphabetical order
893
[email protected]ac294a12012-12-06 16:38:43894 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
895 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28896 """
[email protected]e120b012014-08-15 19:08:35897 def FileFilterIncludeOrder(affected_file):
898 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
899 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28900
901 warnings = []
[email protected]e120b012014-08-15 19:08:35902 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08903 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43904 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
905 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28906
907 results = []
908 if warnings:
[email protected]f7051d52013-04-02 18:31:42909 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53910 warnings))
[email protected]cf9b78f2012-11-14 11:40:28911 return results
912
913
[email protected]70ca77752012-11-20 03:45:03914def _CheckForVersionControlConflictsInFile(input_api, f):
915 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
916 errors = []
917 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23918 if f.LocalPath().endswith('.md'):
919 # First-level headers in markdown look a lot like version control
920 # conflict markers. http://daringfireball.net/projects/markdown/basics
921 continue
[email protected]70ca77752012-11-20 03:45:03922 if pattern.match(line):
923 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
924 return errors
925
926
927def _CheckForVersionControlConflicts(input_api, output_api):
928 """Usually this is not intentional and will cause a compile failure."""
929 errors = []
930 for f in input_api.AffectedFiles():
931 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
932
933 results = []
934 if errors:
935 results.append(output_api.PresubmitError(
936 'Version control conflict markers found, please resolve.', errors))
937 return results
938
939
[email protected]06e6d0ff2012-12-11 01:36:44940def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
941 def FilterFile(affected_file):
942 """Filter function for use with input_api.AffectedSourceFiles,
943 below. This filters out everything except non-test files from
944 top-level directories that generally speaking should not hard-code
945 service URLs (e.g. src/android_webview/, src/content/ and others).
946 """
947 return input_api.FilterSourceFile(
948 affected_file,
[email protected]78bb39d62012-12-11 15:11:56949 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44950 black_list=(_EXCLUDED_PATHS +
951 _TEST_CODE_EXCLUDED_PATHS +
952 input_api.DEFAULT_BLACK_LIST))
953
reillyi38965732015-11-16 18:27:33954 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
955 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46956 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
957 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44958 problems = [] # items are (filename, line_number, line)
959 for f in input_api.AffectedSourceFiles(FilterFile):
960 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46961 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44962 problems.append((f.LocalPath(), line_num, line))
963
964 if problems:
[email protected]f7051d52013-04-02 18:31:42965 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44966 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58967 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44968 [' %s:%d: %s' % (
969 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03970 else:
971 return []
[email protected]06e6d0ff2012-12-11 01:36:44972
973
[email protected]d2530012013-01-25 16:39:27974def _CheckNoAbbreviationInPngFileName(input_api, output_api):
975 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31976 The native_client_sdk directory is excluded because it has auto-generated PNG
977 files for documentation.
[email protected]d2530012013-01-25 16:39:27978 """
[email protected]d2530012013-01-25 16:39:27979 errors = []
binji0dcdf342014-12-12 18:32:31980 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
981 black_list = (r'^native_client_sdk[\\\/]',)
982 file_filter = lambda f: input_api.FilterSourceFile(
983 f, white_list=white_list, black_list=black_list)
984 for f in input_api.AffectedFiles(include_deletes=False,
985 file_filter=file_filter):
986 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27987
988 results = []
989 if errors:
990 results.append(output_api.PresubmitError(
991 'The name of PNG files should not have abbreviations. \n'
992 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
993 'Contact [email protected] if you have questions.', errors))
994 return results
995
996
[email protected]14a6131c2014-01-08 01:15:41997def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08998 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41999 a set of DEPS entries that we should look up.
1000
1001 For a directory (rather than a specific filename) we fake a path to
1002 a specific filename by adding /DEPS. This is chosen as a file that
1003 will seldom or never be subject to per-file include_rules.
1004 """
[email protected]2b438d62013-11-14 17:54:141005 # We ignore deps entries on auto-generated directories.
1006 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081007
1008 # This pattern grabs the path without basename in the first
1009 # parentheses, and the basename (if present) in the second. It
1010 # relies on the simple heuristic that if there is a basename it will
1011 # be a header file ending in ".h".
1012 pattern = re.compile(
1013 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141014 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081015 for changed_line in changed_lines:
1016 m = pattern.match(changed_line)
1017 if m:
1018 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141019 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411020 if m.group(2):
1021 results.add('%s%s' % (path, m.group(2)))
1022 else:
1023 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081024 return results
1025
1026
[email protected]e871964c2013-05-13 14:14:551027def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1028 """When a dependency prefixed with + is added to a DEPS file, we
1029 want to make sure that the change is reviewed by an OWNER of the
1030 target file or directory, to avoid layering violations from being
1031 introduced. This check verifies that this happens.
1032 """
1033 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241034
1035 file_filter = lambda f: not input_api.re.match(
1036 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1037 for f in input_api.AffectedFiles(include_deletes=False,
1038 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551039 filename = input_api.os_path.basename(f.LocalPath())
1040 if filename == 'DEPS':
1041 changed_lines |= set(line.strip()
1042 for line_num, line
1043 in f.ChangedContents())
1044 if not changed_lines:
1045 return []
1046
[email protected]14a6131c2014-01-08 01:15:411047 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1048 changed_lines)
[email protected]e871964c2013-05-13 14:14:551049 if not virtual_depended_on_files:
1050 return []
1051
1052 if input_api.is_committing:
1053 if input_api.tbr:
1054 return [output_api.PresubmitNotifyResult(
1055 '--tbr was specified, skipping OWNERS check for DEPS additions')]
1056 if not input_api.change.issue:
1057 return [output_api.PresubmitError(
1058 "DEPS approval by OWNERS check failed: this change has "
1059 "no Rietveld issue number, so we can't check it for approvals.")]
1060 output = output_api.PresubmitError
1061 else:
1062 output = output_api.PresubmitNotifyResult
1063
1064 owners_db = input_api.owners_db
1065 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1066 input_api,
1067 owners_db.email_regexp,
1068 approval_needed=input_api.is_committing)
1069
1070 owner_email = owner_email or input_api.change.author_email
1071
[email protected]de4f7d22013-05-23 14:27:461072 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511073 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461074 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551075 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1076 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411077
1078 # We strip the /DEPS part that was added by
1079 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1080 # directory.
1081 def StripDeps(path):
1082 start_deps = path.rfind('/DEPS')
1083 if start_deps != -1:
1084 return path[:start_deps]
1085 else:
1086 return path
1087 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551088 for path in missing_files]
1089
1090 if unapproved_dependencies:
1091 output_list = [
[email protected]14a6131c2014-01-08 01:15:411092 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551093 '\n '.join(sorted(unapproved_dependencies)))]
1094 if not input_api.is_committing:
1095 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1096 output_list.append(output(
1097 'Suggested missing target path OWNERS:\n %s' %
1098 '\n '.join(suggested_owners or [])))
1099 return output_list
1100
1101 return []
1102
1103
[email protected]85218562013-11-22 07:41:401104def _CheckSpamLogging(input_api, output_api):
1105 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1106 black_list = (_EXCLUDED_PATHS +
1107 _TEST_CODE_EXCLUDED_PATHS +
1108 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501109 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191110 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481111 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461112 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121113 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1114 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581115 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161116 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031117 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151118 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1119 r"^chromecast[\\\/]",
1120 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311121 r"^components[\\\/]html_viewer[\\\/]"
1122 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461123 # TODO(peter): Remove this exception. https://crbug.com/534537
1124 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1125 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251126 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1127 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111128 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151129 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111130 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521131 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501132 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361133 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311134 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131135 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441136 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451137 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021138 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441139 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401140 source_file_filter = lambda x: input_api.FilterSourceFile(
1141 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1142
1143 log_info = []
1144 printf = []
1145
1146 for f in input_api.AffectedSourceFiles(source_file_filter):
1147 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471148 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401149 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471150 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131151 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371152
mohan.reddyf21db962014-10-16 12:26:471153 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371154 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471155 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401156 printf.append(f.LocalPath())
1157
1158 if log_info:
1159 return [output_api.PresubmitError(
1160 'These files spam the console log with LOG(INFO):',
1161 items=log_info)]
1162 if printf:
1163 return [output_api.PresubmitError(
1164 'These files spam the console log with printf/fprintf:',
1165 items=printf)]
1166 return []
1167
1168
[email protected]49aa76a2013-12-04 06:59:161169def _CheckForAnonymousVariables(input_api, output_api):
1170 """These types are all expected to hold locks while in scope and
1171 so should never be anonymous (which causes them to be immediately
1172 destroyed)."""
1173 they_who_must_be_named = [
1174 'base::AutoLock',
1175 'base::AutoReset',
1176 'base::AutoUnlock',
1177 'SkAutoAlphaRestore',
1178 'SkAutoBitmapShaderInstall',
1179 'SkAutoBlitterChoose',
1180 'SkAutoBounderCommit',
1181 'SkAutoCallProc',
1182 'SkAutoCanvasRestore',
1183 'SkAutoCommentBlock',
1184 'SkAutoDescriptor',
1185 'SkAutoDisableDirectionCheck',
1186 'SkAutoDisableOvalCheck',
1187 'SkAutoFree',
1188 'SkAutoGlyphCache',
1189 'SkAutoHDC',
1190 'SkAutoLockColors',
1191 'SkAutoLockPixels',
1192 'SkAutoMalloc',
1193 'SkAutoMaskFreeImage',
1194 'SkAutoMutexAcquire',
1195 'SkAutoPathBoundsUpdate',
1196 'SkAutoPDFRelease',
1197 'SkAutoRasterClipValidate',
1198 'SkAutoRef',
1199 'SkAutoTime',
1200 'SkAutoTrace',
1201 'SkAutoUnref',
1202 ]
1203 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1204 # bad: base::AutoLock(lock.get());
1205 # not bad: base::AutoLock lock(lock.get());
1206 bad_pattern = input_api.re.compile(anonymous)
1207 # good: new base::AutoLock(lock.get())
1208 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1209 errors = []
1210
1211 for f in input_api.AffectedFiles():
1212 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1213 continue
1214 for linenum, line in f.ChangedContents():
1215 if bad_pattern.search(line) and not good_pattern.search(line):
1216 errors.append('%s:%d' % (f.LocalPath(), linenum))
1217
1218 if errors:
1219 return [output_api.PresubmitError(
1220 'These lines create anonymous variables that need to be named:',
1221 items=errors)]
1222 return []
1223
1224
[email protected]5fe0f8742013-11-29 01:04:591225def _CheckCygwinShell(input_api, output_api):
1226 source_file_filter = lambda x: input_api.FilterSourceFile(
1227 x, white_list=(r'.+\.(gyp|gypi)$',))
1228 cygwin_shell = []
1229
1230 for f in input_api.AffectedSourceFiles(source_file_filter):
1231 for linenum, line in f.ChangedContents():
1232 if 'msvs_cygwin_shell' in line:
1233 cygwin_shell.append(f.LocalPath())
1234 break
1235
1236 if cygwin_shell:
1237 return [output_api.PresubmitError(
1238 'These files should not use msvs_cygwin_shell (the default is 0):',
1239 items=cygwin_shell)]
1240 return []
1241
[email protected]85218562013-11-22 07:41:401242
[email protected]999261d2014-03-03 20:08:081243def _CheckUserActionUpdate(input_api, output_api):
1244 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521245 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081246 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521247 # If actions.xml is already included in the changelist, the PRESUBMIT
1248 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081249 return []
1250
[email protected]999261d2014-03-03 20:08:081251 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1252 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521253 current_actions = None
[email protected]999261d2014-03-03 20:08:081254 for f in input_api.AffectedFiles(file_filter=file_filter):
1255 for line_num, line in f.ChangedContents():
1256 match = input_api.re.search(action_re, line)
1257 if match:
[email protected]2f92dec2014-03-07 19:21:521258 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1259 # loaded only once.
1260 if not current_actions:
1261 with open('tools/metrics/actions/actions.xml') as actions_f:
1262 current_actions = actions_f.read()
1263 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081264 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521265 action = 'name="{0}"'.format(action_name)
1266 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081267 return [output_api.PresubmitPromptWarning(
1268 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521269 'tools/metrics/actions/actions.xml. Please run '
1270 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081271 % (f.LocalPath(), line_num, action_name))]
1272 return []
1273
1274
[email protected]99171a92014-06-03 08:44:471275def _GetJSONParseError(input_api, filename, eat_comments=True):
1276 try:
1277 contents = input_api.ReadFile(filename)
1278 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131279 import sys
1280 original_sys_path = sys.path
1281 try:
1282 sys.path = sys.path + [input_api.os_path.join(
1283 input_api.PresubmitLocalPath(),
1284 'tools', 'json_comment_eater')]
1285 import json_comment_eater
1286 finally:
1287 sys.path = original_sys_path
1288 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471289
1290 input_api.json.loads(contents)
1291 except ValueError as e:
1292 return e
1293 return None
1294
1295
1296def _GetIDLParseError(input_api, filename):
1297 try:
1298 contents = input_api.ReadFile(filename)
1299 idl_schema = input_api.os_path.join(
1300 input_api.PresubmitLocalPath(),
1301 'tools', 'json_schema_compiler', 'idl_schema.py')
1302 process = input_api.subprocess.Popen(
1303 [input_api.python_executable, idl_schema],
1304 stdin=input_api.subprocess.PIPE,
1305 stdout=input_api.subprocess.PIPE,
1306 stderr=input_api.subprocess.PIPE,
1307 universal_newlines=True)
1308 (_, error) = process.communicate(input=contents)
1309 return error or None
1310 except ValueError as e:
1311 return e
1312
1313
1314def _CheckParseErrors(input_api, output_api):
1315 """Check that IDL and JSON files do not contain syntax errors."""
1316 actions = {
1317 '.idl': _GetIDLParseError,
1318 '.json': _GetJSONParseError,
1319 }
1320 # These paths contain test data and other known invalid JSON files.
1321 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491322 r'test[\\\/]data[\\\/]',
1323 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471324 ]
1325 # Most JSON files are preprocessed and support comments, but these do not.
1326 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491327 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471328 ]
1329 # Only run IDL checker on files in these directories.
1330 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491331 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1332 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471333 ]
1334
1335 def get_action(affected_file):
1336 filename = affected_file.LocalPath()
1337 return actions.get(input_api.os_path.splitext(filename)[1])
1338
1339 def MatchesFile(patterns, path):
1340 for pattern in patterns:
1341 if input_api.re.search(pattern, path):
1342 return True
1343 return False
1344
1345 def FilterFile(affected_file):
1346 action = get_action(affected_file)
1347 if not action:
1348 return False
1349 path = affected_file.LocalPath()
1350
1351 if MatchesFile(excluded_patterns, path):
1352 return False
1353
1354 if (action == _GetIDLParseError and
1355 not MatchesFile(idl_included_patterns, path)):
1356 return False
1357 return True
1358
1359 results = []
1360 for affected_file in input_api.AffectedFiles(
1361 file_filter=FilterFile, include_deletes=False):
1362 action = get_action(affected_file)
1363 kwargs = {}
1364 if (action == _GetJSONParseError and
1365 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1366 kwargs['eat_comments'] = False
1367 parse_error = action(input_api,
1368 affected_file.AbsoluteLocalPath(),
1369 **kwargs)
1370 if parse_error:
1371 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1372 (affected_file.LocalPath(), parse_error)))
1373 return results
1374
1375
[email protected]760deea2013-12-10 19:33:491376def _CheckJavaStyle(input_api, output_api):
1377 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471378 import sys
[email protected]760deea2013-12-10 19:33:491379 original_sys_path = sys.path
1380 try:
1381 sys.path = sys.path + [input_api.os_path.join(
1382 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1383 import checkstyle
1384 finally:
1385 # Restore sys.path to what it was before.
1386 sys.path = original_sys_path
1387
1388 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091389 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511390 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491391
1392
dskiba88634f4e2015-08-14 23:03:291393def _CheckAndroidToastUsage(input_api, output_api):
1394 """Checks that code uses org.chromium.ui.widget.Toast instead of
1395 android.widget.Toast (Chromium Toast doesn't force hardware
1396 acceleration on low-end devices, saving memory).
1397 """
1398 toast_import_pattern = input_api.re.compile(
1399 r'^import android\.widget\.Toast;$')
1400
1401 errors = []
1402
1403 sources = lambda affected_file: input_api.FilterSourceFile(
1404 affected_file,
1405 black_list=(_EXCLUDED_PATHS +
1406 _TEST_CODE_EXCLUDED_PATHS +
1407 input_api.DEFAULT_BLACK_LIST +
1408 (r'^chromecast[\\\/].*',
1409 r'^remoting[\\\/].*')),
1410 white_list=(r'.*\.java$',))
1411
1412 for f in input_api.AffectedSourceFiles(sources):
1413 for line_num, line in f.ChangedContents():
1414 if toast_import_pattern.search(line):
1415 errors.append("%s:%d" % (f.LocalPath(), line_num))
1416
1417 results = []
1418
1419 if errors:
1420 results.append(output_api.PresubmitError(
1421 'android.widget.Toast usage is detected. Android toasts use hardware'
1422 ' acceleration, and can be\ncostly on low-end devices. Please use'
1423 ' org.chromium.ui.widget.Toast instead.\n'
1424 'Contact [email protected] if you have any questions.',
1425 errors))
1426
1427 return results
1428
1429
dgnaa68d5e2015-06-10 10:08:221430def _CheckAndroidCrLogUsage(input_api, output_api):
1431 """Checks that new logs using org.chromium.base.Log:
1432 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511433 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221434 """
1435 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121436 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1437 class_in_base_pattern = input_api.re.compile(
1438 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1439 has_some_log_import_pattern = input_api.re.compile(
1440 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221441 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121442 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221443 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511444 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221445 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221446
Vincent Scheib16d7b272015-09-15 18:09:071447 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221448 'or contact [email protected] for more info.')
1449 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121450
dgnaa68d5e2015-06-10 10:08:221451 tag_decl_errors = []
1452 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121453 tag_errors = []
dgn38736db2015-09-18 19:20:511454 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121455 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221456
1457 for f in input_api.AffectedSourceFiles(sources):
1458 file_content = input_api.ReadFile(f)
1459 has_modified_logs = False
1460
1461 # Per line checks
dgn87d9fb62015-06-12 09:15:121462 if (cr_log_import_pattern.search(file_content) or
1463 (class_in_base_pattern.search(file_content) and
1464 not has_some_log_import_pattern.search(file_content))):
1465 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221466 for line_num, line in f.ChangedContents():
1467
1468 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121469 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221470 if match:
1471 has_modified_logs = True
1472
1473 # Make sure it uses "TAG"
1474 if not match.group('tag') == 'TAG':
1475 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121476 else:
1477 # Report non cr Log function calls in changed lines
1478 for line_num, line in f.ChangedContents():
1479 if log_call_pattern.search(line):
1480 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221481
1482 # Per file checks
1483 if has_modified_logs:
1484 # Make sure the tag is using the "cr" prefix and is not too long
1485 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511486 tag_name = match.group('name') if match else None
1487 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221488 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511489 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221490 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511491 elif '.' in tag_name:
1492 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221493
1494 results = []
1495 if tag_decl_errors:
1496 results.append(output_api.PresubmitPromptWarning(
1497 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511498 '"private static final String TAG = "<package tag>".\n'
1499 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221500 tag_decl_errors))
1501
1502 if tag_length_errors:
1503 results.append(output_api.PresubmitError(
1504 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511505 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221506 tag_length_errors))
1507
1508 if tag_errors:
1509 results.append(output_api.PresubmitPromptWarning(
1510 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1511 tag_errors))
1512
dgn87d9fb62015-06-12 09:15:121513 if util_log_errors:
dgn4401aa52015-04-29 16:26:171514 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121515 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1516 util_log_errors))
1517
dgn38736db2015-09-18 19:20:511518 if tag_with_dot_errors:
1519 results.append(output_api.PresubmitPromptWarning(
1520 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1521 tag_with_dot_errors))
1522
dgn4401aa52015-04-29 16:26:171523 return results
1524
1525
agrieve7b6479d82015-10-07 14:24:221526def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1527 """Checks if MDPI assets are placed in a correct directory."""
1528 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1529 ('/res/drawable/' in f.LocalPath() or
1530 '/res/drawable-ldrtl/' in f.LocalPath()))
1531 errors = []
1532 for f in input_api.AffectedFiles(include_deletes=False,
1533 file_filter=file_filter):
1534 errors.append(' %s' % f.LocalPath())
1535
1536 results = []
1537 if errors:
1538 results.append(output_api.PresubmitError(
1539 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1540 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1541 '/res/drawable-ldrtl/.\n'
1542 'Contact [email protected] if you have questions.', errors))
1543 return results
1544
1545
agrievef32bcc72016-04-04 14:57:401546class PydepsChecker(object):
1547 def __init__(self, input_api, pydeps_files):
1548 self._file_cache = {}
1549 self._input_api = input_api
1550 self._pydeps_files = pydeps_files
1551
1552 def _LoadFile(self, path):
1553 """Returns the list of paths within a .pydeps file relative to //."""
1554 if path not in self._file_cache:
1555 with open(path) as f:
1556 self._file_cache[path] = f.read()
1557 return self._file_cache[path]
1558
1559 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1560 """Returns an interable of paths within the .pydep, relativized to //."""
1561 os_path = self._input_api.os_path
1562 pydeps_dir = os_path.dirname(pydeps_path)
1563 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1564 if not l.startswith('*'))
1565 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1566
1567 def _CreateFilesToPydepsMap(self):
1568 """Returns a map of local_path -> list_of_pydeps."""
1569 ret = {}
1570 for pydep_local_path in self._pydeps_files:
1571 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1572 ret.setdefault(path, []).append(pydep_local_path)
1573 return ret
1574
1575 def ComputeAffectedPydeps(self):
1576 """Returns an iterable of .pydeps files that might need regenerating."""
1577 affected_pydeps = set()
1578 file_to_pydeps_map = None
1579 for f in self._input_api.AffectedFiles(include_deletes=True):
1580 local_path = f.LocalPath()
1581 if local_path == 'DEPS':
1582 return self._pydeps_files
1583 elif local_path.endswith('.pydeps'):
1584 if local_path in self._pydeps_files:
1585 affected_pydeps.add(local_path)
1586 elif local_path.endswith('.py'):
1587 if file_to_pydeps_map is None:
1588 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1589 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1590 return affected_pydeps
1591
1592 def DetermineIfStale(self, pydeps_path):
1593 """Runs print_python_deps.py to see if the files is stale."""
1594 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1595 cmd = old_pydeps_data[1][1:].strip()
1596 new_pydeps_data = self._input_api.subprocess.check_output(
1597 cmd + ' --output ""', shell=True)
1598 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1599 return cmd
1600
1601
1602def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1603 """Checks if a .pydeps file needs to be regenerated."""
1604 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1605 is_android = input_api.os_path.exists('third_party/android_tools')
1606 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1607 results = []
1608 # First, check for new / deleted .pydeps.
1609 for f in input_api.AffectedFiles(include_deletes=True):
1610 if f.LocalPath().endswith('.pydeps'):
1611 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1612 results.append(output_api.PresubmitError(
1613 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1614 'remove %s' % f.LocalPath()))
1615 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1616 results.append(output_api.PresubmitError(
1617 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1618 'include %s' % f.LocalPath()))
1619
1620 if results:
1621 return results
1622
1623 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1624
1625 for pydep_path in checker.ComputeAffectedPydeps():
1626 try:
1627 cmd = checker.DetermineIfStale(pydep_path)
1628 if cmd:
1629 results.append(output_api.PresubmitError(
1630 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1631 (pydep_path, cmd)))
1632 except input_api.subprocess.CalledProcessError as error:
1633 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1634 long_text=error.output)]
1635
1636 return results
1637
1638
mnaganov9b9b1fe82014-12-11 16:30:361639def _CheckForCopyrightedCode(input_api, output_api):
1640 """Verifies that newly added code doesn't contain copyrighted material
1641 and is properly licensed under the standard Chromium license.
1642
1643 As there can be false positives, we maintain a whitelist file. This check
1644 also verifies that the whitelist file is up to date.
1645 """
1646 import sys
1647 original_sys_path = sys.path
1648 try:
1649 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221650 input_api.PresubmitLocalPath(), 'tools')]
1651 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361652 finally:
1653 # Restore sys.path to what it was before.
1654 sys.path = original_sys_path
1655
1656 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1657
1658
glidere61efad2015-02-18 17:39:431659def _CheckSingletonInHeaders(input_api, output_api):
1660 """Checks to make sure no header files have |Singleton<|."""
1661 def FileFilter(affected_file):
1662 # It's ok for base/memory/singleton.h to have |Singleton<|.
1663 black_list = (_EXCLUDED_PATHS +
1664 input_api.DEFAULT_BLACK_LIST +
1665 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1666 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1667
sergeyu34d21222015-09-16 00:11:441668 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431669 files = []
1670 for f in input_api.AffectedSourceFiles(FileFilter):
1671 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1672 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1673 contents = input_api.ReadFile(f)
1674 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241675 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431676 pattern.search(line)):
1677 files.append(f)
1678 break
1679
1680 if files:
yolandyandaabc6d2016-04-18 18:29:391681 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441682 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431683 'Please move them to an appropriate source file so that the ' +
1684 'template gets instantiated in a single compilation unit.',
1685 files) ]
1686 return []
1687
1688
dbeam37e8e7402016-02-10 22:58:201689def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1690 """Checks for old style compiled_resources.gyp files."""
1691 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1692
1693 added_compiled_resources = filter(is_compiled_resource, [
1694 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1695 ])
1696
1697 if not added_compiled_resources:
1698 return []
1699
1700 return [output_api.PresubmitError(
1701 "Found new compiled_resources.gyp files:\n%s\n\n"
1702 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551703 "please use compiled_resources2.gyp instead:\n"
1704 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1705 %
dbeam37e8e7402016-02-10 22:58:201706 "\n".join(added_compiled_resources))]
1707
1708
[email protected]fd20b902014-05-09 02:14:531709_DEPRECATED_CSS = [
1710 # Values
1711 ( "-webkit-box", "flex" ),
1712 ( "-webkit-inline-box", "inline-flex" ),
1713 ( "-webkit-flex", "flex" ),
1714 ( "-webkit-inline-flex", "inline-flex" ),
1715 ( "-webkit-min-content", "min-content" ),
1716 ( "-webkit-max-content", "max-content" ),
1717
1718 # Properties
1719 ( "-webkit-background-clip", "background-clip" ),
1720 ( "-webkit-background-origin", "background-origin" ),
1721 ( "-webkit-background-size", "background-size" ),
1722 ( "-webkit-box-shadow", "box-shadow" ),
1723
1724 # Functions
1725 ( "-webkit-gradient", "gradient" ),
1726 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1727 ( "-webkit-linear-gradient", "linear-gradient" ),
1728 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1729 ( "-webkit-radial-gradient", "radial-gradient" ),
1730 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1731]
1732
1733def _CheckNoDeprecatedCSS(input_api, output_api):
1734 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251735 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341736 documentation and iOS CSS for dom distiller
1737 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251738 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531739 results = []
dbeam070cfe62014-10-22 06:44:021740 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251741 black_list = (_EXCLUDED_PATHS +
1742 _TEST_CODE_EXCLUDED_PATHS +
1743 input_api.DEFAULT_BLACK_LIST +
1744 (r"^chrome/common/extensions/docs",
1745 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341746 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051747 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441748 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251749 r"^native_client_sdk"))
1750 file_filter = lambda f: input_api.FilterSourceFile(
1751 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531752 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1753 for line_num, line in fpath.ChangedContents():
1754 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021755 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531756 results.append(output_api.PresubmitError(
1757 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1758 (fpath.LocalPath(), line_num, deprecated_value, value)))
1759 return results
1760
mohan.reddyf21db962014-10-16 12:26:471761
dbeam070cfe62014-10-22 06:44:021762_DEPRECATED_JS = [
1763 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1764 ( "__defineGetter__", "Object.defineProperty" ),
1765 ( "__defineSetter__", "Object.defineProperty" ),
1766]
1767
1768def _CheckNoDeprecatedJS(input_api, output_api):
1769 """Make sure that we don't use deprecated JS in Chrome code."""
1770 results = []
1771 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1772 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1773 input_api.DEFAULT_BLACK_LIST)
1774 file_filter = lambda f: input_api.FilterSourceFile(
1775 f, white_list=file_inclusion_pattern, black_list=black_list)
1776 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1777 for lnum, line in fpath.ChangedContents():
1778 for (deprecated, replacement) in _DEPRECATED_JS:
1779 if deprecated in line:
1780 results.append(output_api.PresubmitError(
1781 "%s:%d: Use of deprecated JS %s, use %s instead" %
1782 (fpath.LocalPath(), lnum, deprecated, replacement)))
1783 return results
1784
1785
dgnaa68d5e2015-06-10 10:08:221786def _AndroidSpecificOnUploadChecks(input_api, output_api):
1787 """Groups checks that target android code."""
1788 results = []
dgnaa68d5e2015-06-10 10:08:221789 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221790 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291791 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221792 return results
1793
1794
[email protected]22c9bd72011-03-27 16:47:391795def _CommonChecks(input_api, output_api):
1796 """Checks common to both upload and commit."""
1797 results = []
1798 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381799 input_api, output_api,
1800 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461801 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191802 results.extend(
[email protected]760deea2013-12-10 19:33:491803 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541804 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181805 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521806 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221807 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441808 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591809 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061810 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121811 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181812 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221813 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491814 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271815 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031816 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491817 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441818 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271819 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541820 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441821 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391822 results.extend(_CheckFlakyTestUsage(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461823 # TODO(danakj): Remove this when base/move.h is removed.
dchengcf95c122015-12-18 08:29:161824 results.extend(_CheckForUsingPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551825 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041826 results.extend(
1827 input_api.canned_checks.CheckChangeHasNoTabs(
1828 input_api,
1829 output_api,
1830 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401831 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161832 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591833 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081834 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531835 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021836 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471837 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041838 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361839 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231840 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431841 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201842 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401843 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241844
1845 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1846 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1847 input_api, output_api,
1848 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381849 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391850 return results
[email protected]1f7b4172010-01-28 01:17:341851
[email protected]b337cb5b2011-01-23 21:24:051852
[email protected]66daa702011-05-28 14:41:461853def _CheckAuthorizedAuthor(input_api, output_api):
1854 """For non-googler/chromites committers, verify the author's email address is
1855 in AUTHORS.
1856 """
[email protected]9bb9cb82011-06-13 20:43:011857 # TODO(maruel): Add it to input_api?
1858 import fnmatch
1859
[email protected]66daa702011-05-28 14:41:461860 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011861 if not author:
1862 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461863 return []
[email protected]c99663292011-05-31 19:46:081864 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461865 input_api.PresubmitLocalPath(), 'AUTHORS')
1866 valid_authors = (
1867 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1868 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181869 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441870 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231871 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461872 return [output_api.PresubmitPromptWarning(
1873 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1874 '\n'
1875 'http://www.chromium.org/developers/contributing-code and read the '
1876 '"Legal" section\n'
1877 'If you are a chromite, verify the contributor signed the CLA.') %
1878 author)]
1879 return []
1880
1881
[email protected]b8079ae4a2012-12-05 19:56:491882def _CheckPatchFiles(input_api, output_api):
1883 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1884 if f.LocalPath().endswith(('.orig', '.rej'))]
1885 if problems:
1886 return [output_api.PresubmitError(
1887 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031888 else:
1889 return []
[email protected]b8079ae4a2012-12-05 19:56:491890
1891
[email protected]b00342e7f2013-03-26 16:21:541892def _DidYouMeanOSMacro(bad_macro):
1893 try:
1894 return {'A': 'OS_ANDROID',
1895 'B': 'OS_BSD',
1896 'C': 'OS_CHROMEOS',
1897 'F': 'OS_FREEBSD',
1898 'L': 'OS_LINUX',
1899 'M': 'OS_MACOSX',
1900 'N': 'OS_NACL',
1901 'O': 'OS_OPENBSD',
1902 'P': 'OS_POSIX',
1903 'S': 'OS_SOLARIS',
1904 'W': 'OS_WIN'}[bad_macro[3].upper()]
1905 except KeyError:
1906 return ''
1907
1908
1909def _CheckForInvalidOSMacrosInFile(input_api, f):
1910 """Check for sensible looking, totally invalid OS macros."""
1911 preprocessor_statement = input_api.re.compile(r'^\s*#')
1912 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1913 results = []
1914 for lnum, line in f.ChangedContents():
1915 if preprocessor_statement.search(line):
1916 for match in os_macro.finditer(line):
1917 if not match.group(1) in _VALID_OS_MACROS:
1918 good = _DidYouMeanOSMacro(match.group(1))
1919 did_you_mean = ' (did you mean %s?)' % good if good else ''
1920 results.append(' %s:%d %s%s' % (f.LocalPath(),
1921 lnum,
1922 match.group(1),
1923 did_you_mean))
1924 return results
1925
1926
1927def _CheckForInvalidOSMacros(input_api, output_api):
1928 """Check all affected files for invalid OS macros."""
1929 bad_macros = []
1930 for f in input_api.AffectedFiles():
1931 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1932 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1933
1934 if not bad_macros:
1935 return []
1936
1937 return [output_api.PresubmitError(
1938 'Possibly invalid OS macro[s] found. Please fix your code\n'
1939 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1940
lliabraa35bab3932014-10-01 12:16:441941
1942def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1943 """Check all affected files for invalid "if defined" macros."""
1944 ALWAYS_DEFINED_MACROS = (
1945 "TARGET_CPU_PPC",
1946 "TARGET_CPU_PPC64",
1947 "TARGET_CPU_68K",
1948 "TARGET_CPU_X86",
1949 "TARGET_CPU_ARM",
1950 "TARGET_CPU_MIPS",
1951 "TARGET_CPU_SPARC",
1952 "TARGET_CPU_ALPHA",
1953 "TARGET_IPHONE_SIMULATOR",
1954 "TARGET_OS_EMBEDDED",
1955 "TARGET_OS_IPHONE",
1956 "TARGET_OS_MAC",
1957 "TARGET_OS_UNIX",
1958 "TARGET_OS_WIN32",
1959 )
1960 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1961 results = []
1962 for lnum, line in f.ChangedContents():
1963 for match in ifdef_macro.finditer(line):
1964 if match.group(1) in ALWAYS_DEFINED_MACROS:
1965 always_defined = ' %s is always defined. ' % match.group(1)
1966 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1967 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1968 lnum,
1969 always_defined,
1970 did_you_mean))
1971 return results
1972
1973
1974def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1975 """Check all affected files for invalid "if defined" macros."""
1976 bad_macros = []
1977 for f in input_api.AffectedFiles():
1978 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1979 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1980
1981 if not bad_macros:
1982 return []
1983
1984 return [output_api.PresubmitError(
1985 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1986 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1987 bad_macros)]
1988
1989
dchengcf95c122015-12-18 08:29:161990def _CheckForUsingPass(input_api, output_api):
danakj3c84d0c2014-10-06 15:35:461991 """Check all affected files for using side effects of Pass."""
1992 errors = []
1993 for f in input_api.AffectedFiles():
1994 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1995 for lnum, line in f.ChangedContents():
dchengcf95c122015-12-18 08:29:161996 # Warn on any use of foo.Pass().
1997 if input_api.re.search(r'[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461998 errors.append(output_api.PresubmitError(
dchengcf95c122015-12-18 08:29:161999 ('%s:%d uses Pass(); please use std::move() instead. ' +
2000 'See crbug.com/557422.') % (f.LocalPath(), lnum)))
danakj3c84d0c2014-10-06 15:35:462001 return errors
2002
2003
mlamouria82272622014-09-16 18:45:042004def _CheckForIPCRules(input_api, output_api):
2005 """Check for same IPC rules described in
2006 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2007 """
2008 base_pattern = r'IPC_ENUM_TRAITS\('
2009 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2010 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2011
2012 problems = []
2013 for f in input_api.AffectedSourceFiles(None):
2014 local_path = f.LocalPath()
2015 if not local_path.endswith('.h'):
2016 continue
2017 for line_number, line in f.ChangedContents():
2018 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2019 problems.append(
2020 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2021
2022 if problems:
2023 return [output_api.PresubmitPromptWarning(
2024 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2025 else:
2026 return []
2027
[email protected]b00342e7f2013-03-26 16:21:542028
mostynbb639aca52015-01-07 20:31:232029def _CheckForWindowsLineEndings(input_api, output_api):
2030 """Check source code and known ascii text files for Windows style line
2031 endings.
2032 """
earthdok1b5e0ee2015-03-10 15:19:102033 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232034
2035 file_inclusion_pattern = (
2036 known_text_files,
2037 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2038 )
2039
2040 filter = lambda f: input_api.FilterSourceFile(
2041 f, white_list=file_inclusion_pattern, black_list=None)
2042 files = [f.LocalPath() for f in
2043 input_api.AffectedSourceFiles(filter)]
2044
2045 problems = []
2046
2047 for file in files:
2048 fp = open(file, 'r')
2049 for line in fp:
2050 if line.endswith('\r\n'):
2051 problems.append(file)
2052 break
2053 fp.close()
2054
2055 if problems:
2056 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2057 'these files to contain Windows style line endings?\n' +
2058 '\n'.join(problems))]
2059
2060 return []
2061
2062
[email protected]1f7b4172010-01-28 01:17:342063def CheckChangeOnUpload(input_api, output_api):
2064 results = []
2065 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472066 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:172067 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:282068 results.extend(
2069 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192070 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222071 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542072 return results
[email protected]ca8d1982009-02-19 16:33:122073
2074
[email protected]1bfb8322014-04-23 01:02:412075def GetTryServerMasterForBot(bot):
2076 """Returns the Try Server master for the given bot.
2077
[email protected]0bb112362014-07-26 04:38:322078 It tries to guess the master from the bot name, but may still fail
2079 and return None. There is no longer a default master.
2080 """
2081 # Potentially ambiguous bot names are listed explicitly.
2082 master_map = {
[email protected]0bb112362014-07-26 04:38:322083 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322084 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412085 }
[email protected]0bb112362014-07-26 04:38:322086 master = master_map.get(bot)
2087 if not master:
sergiyb37fd293f2015-02-26 06:55:012088 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322089 master = 'tryserver.chromium.linux'
2090 elif 'win' in bot:
2091 master = 'tryserver.chromium.win'
2092 elif 'mac' in bot or 'ios' in bot:
2093 master = 'tryserver.chromium.mac'
2094 return master
[email protected]1bfb8322014-04-23 01:02:412095
2096
Paweł Hajdan, Jr55083782014-12-19 20:32:562097def GetDefaultTryConfigs(bots):
2098 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012099 """
2100
Paweł Hajdan, Jr55083782014-12-19 20:32:562101 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412102
2103 # Build up the mapping from tryserver master to bot/test.
2104 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562105 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412106 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2107 return out
[email protected]38c6a512013-12-18 23:48:012108
2109
[email protected]ca8d1982009-02-19 16:33:122110def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542111 results = []
[email protected]1f7b4172010-01-28 01:17:342112 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542113 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272114 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342115 input_api,
2116 output_api,
[email protected]2fdd1f362013-01-16 03:56:032117 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272118
[email protected]3e4eb112011-01-18 03:29:542119 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2120 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412121 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2122 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542123 return results