blob: d60a19cccd0d687f102d1be589593b36cae4421e [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d19842009-02-19 16:33:1227
wnwenbdc444e2016-05-25 13:44:1528
jochen9ea8fdbc2014-09-25 13:21:3529# The NetscapePlugIn library is excluded from pan-project as it will soon
30# be deleted together with the rest of the NPAPI and it's not worthwhile to
31# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3832_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3233 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3834)
35
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Fragment of a regular expression that matches C++ and Objective-C++
38# implementation files.
39_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
40
wnwenbdc444e2016-05-25 13:44:1541
[email protected]06e6d0ff2012-12-11 01:36:4442# Regular expression that matches code only used for test binaries
43# (best effort).
44_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4945 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3247 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1248 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4449 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4950 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0551 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4952 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4453 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4954 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4956 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4958 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d19842009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
[email protected]127f18ec2012-06-16 05:05:5975_BANNED_OBJC_FUNCTIONS = (
76 (
77 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2078 (
79 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5980 'prohibited. Please use CrTrackingArea instead.',
81 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
82 ),
83 False,
84 ),
85 (
[email protected]eaae1972014-04-16 04:17:2686 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2087 (
88 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5989 'instead.',
90 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
91 ),
92 False,
93 ),
94 (
95 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2096 (
97 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5998 'Please use |convertPoint:(point) fromView:nil| instead.',
99 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
100 ),
101 True,
102 ),
103 (
104 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20105 (
106 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59107 'Please use |convertPoint:(point) toView:nil| instead.',
108 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
109 ),
110 True,
111 ),
112 (
113 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20114 (
115 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59116 'Please use |convertRect:(point) fromView:nil| instead.',
117 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
118 ),
119 True,
120 ),
121 (
122 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20123 (
124 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59125 'Please use |convertRect:(point) toView:nil| instead.',
126 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
127 ),
128 True,
129 ),
130 (
131 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20132 (
133 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59134 'Please use |convertSize:(point) fromView:nil| instead.',
135 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
136 ),
137 True,
138 ),
139 (
140 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20141 (
142 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59143 'Please use |convertSize:(point) toView:nil| instead.',
144 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
145 ),
146 True,
147 ),
148)
149
150
151_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20152 # Make sure that gtest's FRIEND_TEST() macro is not used; the
153 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30154 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'FRIEND_TEST(',
157 (
[email protected]e3c945502012-06-26 20:01:49158 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20159 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
160 ),
161 False,
[email protected]7345da02012-11-27 14:31:49162 (),
[email protected]23e6cbc2012-06-16 18:51:20163 ),
164 (
165 'ScopedAllowIO',
166 (
[email protected]e3c945502012-06-26 20:01:49167 'New code should not use ScopedAllowIO. Post a task to the blocking',
168 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20169 ),
[email protected]e3c945502012-06-26 20:01:49170 True,
[email protected]7345da02012-11-27 14:31:49171 (
nyad2c548b2015-12-09 03:22:32172 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10173 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49174 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22175 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31176 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51177 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
178 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09179 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49180 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
181 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41182 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
183 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48184 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
185 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01186 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54187 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13188 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
189 "gnubby_auth_handler_linux\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53190 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
191 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45192 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
193 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
194 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
195 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
196 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49197 ),
[email protected]23e6cbc2012-06-16 18:51:20198 ),
[email protected]52657f62013-05-20 05:30:31199 (
tomhudsone2c14d552016-05-26 17:07:46200 'setMatrixClip',
201 (
202 'Overriding setMatrixClip() is prohibited; ',
203 'the base function is deprecated. ',
204 ),
205 True,
206 (),
207 ),
208 (
[email protected]52657f62013-05-20 05:30:31209 'SkRefPtr',
210 (
211 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22212 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31213 ),
214 True,
215 (),
216 ),
217 (
218 'SkAutoRef',
219 (
220 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22221 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31222 ),
223 True,
224 (),
225 ),
226 (
227 'SkAutoTUnref',
228 (
229 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22230 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31231 ),
232 True,
233 (),
234 ),
235 (
236 'SkAutoUnref',
237 (
238 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
239 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22240 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31241 ),
242 True,
243 (),
244 ),
[email protected]d89eec82013-12-03 14:10:59245 (
246 r'/HANDLE_EINTR\(.*close',
247 (
248 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
249 'descriptor will be closed, and it is incorrect to retry the close.',
250 'Either call close directly and ignore its return value, or wrap close',
251 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
252 ),
253 True,
254 (),
255 ),
256 (
257 r'/IGNORE_EINTR\((?!.*close)',
258 (
259 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
260 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
261 ),
262 True,
263 (
264 # Files that #define IGNORE_EINTR.
265 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
266 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
267 ),
268 ),
[email protected]ec5b3f02014-04-04 18:43:43269 (
270 r'/v8::Extension\(',
271 (
272 'Do not introduce new v8::Extensions into the code base, use',
273 'gin::Wrappable instead. See http://crbug.com/334679',
274 ),
275 True,
[email protected]f55c90ee62014-04-12 00:50:03276 (
joaodasilva718f87672014-08-30 09:25:49277 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03278 ),
[email protected]ec5b3f02014-04-04 18:43:43279 ),
skyostilf9469f72015-04-20 10:38:52280 (
jame2d1a952016-04-02 00:27:10281 '#pragma comment(lib,',
282 (
283 'Specify libraries to link with in build files and not in the source.',
284 ),
285 True,
286 (),
287 ),
[email protected]127f18ec2012-06-16 05:05:59288)
289
wnwenbdc444e2016-05-25 13:44:15290
mlamouria82272622014-09-16 18:45:04291_IPC_ENUM_TRAITS_DEPRECATED = (
292 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
293 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
294
[email protected]127f18ec2012-06-16 05:05:59295
[email protected]b00342e7f2013-03-26 16:21:54296_VALID_OS_MACROS = (
297 # Please keep sorted.
298 'OS_ANDROID',
299 'OS_BSD',
300 'OS_CAT', # For testing.
301 'OS_CHROMEOS',
302 'OS_FREEBSD',
303 'OS_IOS',
304 'OS_LINUX',
305 'OS_MACOSX',
306 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21307 'OS_NACL_NONSFI',
308 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54309 'OS_OPENBSD',
310 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37311 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54312 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54313 'OS_WIN',
314)
315
316
agrievef32bcc72016-04-04 14:57:40317_ANDROID_SPECIFIC_PYDEPS_FILES = [
318 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19319 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40320]
321
wnwenbdc444e2016-05-25 13:44:15322
agrievef32bcc72016-04-04 14:57:40323_GENERIC_PYDEPS_FILES = [
324 'build/secondary/tools/swarming_client/isolate.pydeps',
325]
326
wnwenbdc444e2016-05-25 13:44:15327
agrievef32bcc72016-04-04 14:57:40328_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
329
330
[email protected]55459852011-08-10 15:17:19331def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
332 """Attempts to prevent use of functions intended only for testing in
333 non-testing code. For now this is just a best-effort implementation
334 that ignores header files and may have some false positives. A
335 better implementation would probably need a proper C++ parser.
336 """
337 # We only scan .cc files and the like, as the declaration of
338 # for-testing functions in header files are hard to distinguish from
339 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44340 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19341
jochenc0d4808c2015-07-27 09:25:42342 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19343 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09344 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19345 exclusion_pattern = input_api.re.compile(
346 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
347 base_function_pattern, base_function_pattern))
348
349 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44350 black_list = (_EXCLUDED_PATHS +
351 _TEST_CODE_EXCLUDED_PATHS +
352 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19353 return input_api.FilterSourceFile(
354 affected_file,
355 white_list=(file_inclusion_pattern, ),
356 black_list=black_list)
357
358 problems = []
359 for f in input_api.AffectedSourceFiles(FilterFile):
360 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24361 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03362 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46363 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03364 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19365 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03366 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19367
368 if problems:
[email protected]f7051d52013-04-02 18:31:42369 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03370 else:
371 return []
[email protected]55459852011-08-10 15:17:19372
373
[email protected]10689ca2011-09-02 02:31:54374def _CheckNoIOStreamInHeaders(input_api, output_api):
375 """Checks to make sure no .h files include <iostream>."""
376 files = []
377 pattern = input_api.re.compile(r'^#include\s*<iostream>',
378 input_api.re.MULTILINE)
379 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
380 if not f.LocalPath().endswith('.h'):
381 continue
382 contents = input_api.ReadFile(f)
383 if pattern.search(contents):
384 files.append(f)
385
386 if len(files):
yolandyandaabc6d2016-04-18 18:29:39387 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06388 'Do not #include <iostream> in header files, since it inserts static '
389 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54390 '#include <ostream>. See http://crbug.com/94794',
391 files) ]
392 return []
393
394
[email protected]72df4e782012-06-21 16:28:18395def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52396 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18397 problems = []
398 for f in input_api.AffectedFiles():
399 if (not f.LocalPath().endswith(('.cc', '.mm'))):
400 continue
401
402 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04403 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18404 problems.append(' %s:%d' % (f.LocalPath(), line_num))
405
406 if not problems:
407 return []
408 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
409 '\n'.join(problems))]
410
411
danakj61c1aa22015-10-26 19:55:52412def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
413 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
414 errors = []
415 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
416 input_api.re.MULTILINE)
417 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
418 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
419 continue
420 for lnum, line in f.ChangedContents():
421 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17422 errors.append(output_api.PresubmitError(
423 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
424 'DCHECK_IS_ON()", not forgetting the braces.')
425 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52426 return errors
427
428
mcasasb7440c282015-02-04 14:52:19429def _FindHistogramNameInLine(histogram_name, line):
430 """Tries to find a histogram name or prefix in a line."""
431 if not "affected-histogram" in line:
432 return histogram_name in line
433 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
434 # the histogram_name.
435 if not '"' in line:
436 return False
437 histogram_prefix = line.split('\"')[1]
438 return histogram_prefix in histogram_name
439
440
441def _CheckUmaHistogramChanges(input_api, output_api):
442 """Check that UMA histogram names in touched lines can still be found in other
443 lines of the patch or in histograms.xml. Note that this check would not catch
444 the reverse: changes in histograms.xml not matched in the code itself."""
445 touched_histograms = []
446 histograms_xml_modifications = []
447 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
448 for f in input_api.AffectedFiles():
449 # If histograms.xml itself is modified, keep the modified lines for later.
450 if f.LocalPath().endswith(('histograms.xml')):
451 histograms_xml_modifications = f.ChangedContents()
452 continue
453 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
454 continue
455 for line_num, line in f.ChangedContents():
456 found = pattern.search(line)
457 if found:
458 touched_histograms.append([found.group(1), f, line_num])
459
460 # Search for the touched histogram names in the local modifications to
461 # histograms.xml, and, if not found, on the base histograms.xml file.
462 unmatched_histograms = []
463 for histogram_info in touched_histograms:
464 histogram_name_found = False
465 for line_num, line in histograms_xml_modifications:
466 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
467 if histogram_name_found:
468 break
469 if not histogram_name_found:
470 unmatched_histograms.append(histogram_info)
471
eromanb90c82e7e32015-04-01 15:13:49472 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19473 problems = []
474 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49475 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19476 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45477 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19478 histogram_name_found = False
479 for line in histograms_xml:
480 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
481 if histogram_name_found:
482 break
483 if not histogram_name_found:
484 problems.append(' [%s:%d] %s' %
485 (f.LocalPath(), line_num, histogram_name))
486
487 if not problems:
488 return []
489 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
490 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49491 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19492
wnwenbdc444e2016-05-25 13:44:15493
yolandyandaabc6d2016-04-18 18:29:39494def _CheckFlakyTestUsage(input_api, output_api):
495 """Check that FlakyTest annotation is our own instead of the android one"""
496 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
497 files = []
498 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
499 if f.LocalPath().endswith('Test.java'):
500 if pattern.search(input_api.ReadFile(f)):
501 files.append(f)
502 if len(files):
503 return [output_api.PresubmitError(
504 'Use org.chromium.base.test.util.FlakyTest instead of '
505 'android.test.FlakyTest',
506 files)]
507 return []
mcasasb7440c282015-02-04 14:52:19508
wnwenbdc444e2016-05-25 13:44:15509
[email protected]8ea5d4b2011-09-13 21:49:22510def _CheckNoNewWStrings(input_api, output_api):
511 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27512 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22513 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20514 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57515 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
516 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20517 continue
[email protected]8ea5d4b2011-09-13 21:49:22518
[email protected]a11dbe9b2012-08-07 01:32:58519 allowWString = False
[email protected]b5c24292011-11-28 14:38:20520 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58521 if 'presubmit: allow wstring' in line:
522 allowWString = True
523 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27524 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58525 allowWString = False
526 else:
527 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22528
[email protected]55463aa62011-10-12 00:48:27529 if not problems:
530 return []
531 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58532 ' If you are calling a cross-platform API that accepts a wstring, '
533 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27534 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22535
536
[email protected]2a8ac9c2011-10-19 17:20:44537def _CheckNoDEPSGIT(input_api, output_api):
538 """Make sure .DEPS.git is never modified manually."""
539 if any(f.LocalPath().endswith('.DEPS.git') for f in
540 input_api.AffectedFiles()):
541 return [output_api.PresubmitError(
542 'Never commit changes to .DEPS.git. This file is maintained by an\n'
543 'automated system based on what\'s in DEPS and your changes will be\n'
544 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34545 '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:44546 'for more information')]
547 return []
548
549
tandriief664692014-09-23 14:51:47550def _CheckValidHostsInDEPS(input_api, output_api):
551 """Checks that DEPS file deps are from allowed_hosts."""
552 # Run only if DEPS file has been modified to annoy fewer bystanders.
553 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
554 return []
555 # Outsource work to gclient verify
556 try:
557 input_api.subprocess.check_output(['gclient', 'verify'])
558 return []
559 except input_api.subprocess.CalledProcessError, error:
560 return [output_api.PresubmitError(
561 'DEPS file must have only git dependencies.',
562 long_text=error.output)]
563
564
[email protected]127f18ec2012-06-16 05:05:59565def _CheckNoBannedFunctions(input_api, output_api):
566 """Make sure that banned functions are not used."""
567 warnings = []
568 errors = []
569
wnwenbdc444e2016-05-25 13:44:15570 def IsBlacklisted(affected_file, blacklist):
571 local_path = affected_file.LocalPath()
572 for item in blacklist:
573 if input_api.re.match(item, local_path):
574 return True
575 return False
576
577 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
578 matched = False
579 if func_name[0:1] == '/':
580 regex = func_name[1:]
581 if input_api.re.search(regex, line):
582 matched = True
583 elif func_name in line:
dchenge07de812016-06-20 19:27:17584 matched = True
wnwenbdc444e2016-05-25 13:44:15585 if matched:
dchenge07de812016-06-20 19:27:17586 problems = warnings
wnwenbdc444e2016-05-25 13:44:15587 if error:
dchenge07de812016-06-20 19:27:17588 problems = errors
wnwenbdc444e2016-05-25 13:44:15589 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
590 for message_line in message:
591 problems.append(' %s' % message_line)
592
[email protected]127f18ec2012-06-16 05:05:59593 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
594 for f in input_api.AffectedFiles(file_filter=file_filter):
595 for line_num, line in f.ChangedContents():
596 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15597 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59598
599 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
600 for f in input_api.AffectedFiles(file_filter=file_filter):
601 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49602 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49603 if IsBlacklisted(f, excluded_paths):
604 continue
wnwenbdc444e2016-05-25 13:44:15605 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59606
607 result = []
608 if (warnings):
609 result.append(output_api.PresubmitPromptWarning(
610 'Banned functions were used.\n' + '\n'.join(warnings)))
611 if (errors):
612 result.append(output_api.PresubmitError(
613 'Banned functions were used.\n' + '\n'.join(errors)))
614 return result
615
616
[email protected]6c063c62012-07-11 19:11:06617def _CheckNoPragmaOnce(input_api, output_api):
618 """Make sure that banned functions are not used."""
619 files = []
620 pattern = input_api.re.compile(r'^#pragma\s+once',
621 input_api.re.MULTILINE)
622 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
623 if not f.LocalPath().endswith('.h'):
624 continue
625 contents = input_api.ReadFile(f)
626 if pattern.search(contents):
627 files.append(f)
628
629 if files:
630 return [output_api.PresubmitError(
631 'Do not use #pragma once in header files.\n'
632 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
633 files)]
634 return []
635
[email protected]127f18ec2012-06-16 05:05:59636
[email protected]e7479052012-09-19 00:26:12637def _CheckNoTrinaryTrueFalse(input_api, output_api):
638 """Checks to make sure we don't introduce use of foo ? true : false."""
639 problems = []
640 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
641 for f in input_api.AffectedFiles():
642 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
643 continue
644
645 for line_num, line in f.ChangedContents():
646 if pattern.match(line):
647 problems.append(' %s:%d' % (f.LocalPath(), line_num))
648
649 if not problems:
650 return []
651 return [output_api.PresubmitPromptWarning(
652 'Please consider avoiding the "? true : false" pattern if possible.\n' +
653 '\n'.join(problems))]
654
655
[email protected]55f9f382012-07-31 11:02:18656def _CheckUnwantedDependencies(input_api, output_api):
657 """Runs checkdeps on #include statements added in this
658 change. Breaking - rules is an error, breaking ! rules is a
659 warning.
660 """
mohan.reddyf21db962014-10-16 12:26:47661 import sys
[email protected]55f9f382012-07-31 11:02:18662 # We need to wait until we have an input_api object and use this
663 # roundabout construct to import checkdeps because this file is
664 # eval-ed and thus doesn't have __file__.
665 original_sys_path = sys.path
666 try:
667 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47668 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18669 import checkdeps
670 from cpp_checker import CppChecker
671 from rules import Rule
672 finally:
673 # Restore sys.path to what it was before.
674 sys.path = original_sys_path
675
676 added_includes = []
677 for f in input_api.AffectedFiles():
678 if not CppChecker.IsCppFile(f.LocalPath()):
679 continue
680
681 changed_lines = [line for line_num, line in f.ChangedContents()]
682 added_includes.append([f.LocalPath(), changed_lines])
683
[email protected]26385172013-05-09 23:11:35684 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18685
686 error_descriptions = []
687 warning_descriptions = []
688 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
689 added_includes):
690 description_with_path = '%s\n %s' % (path, rule_description)
691 if rule_type == Rule.DISALLOW:
692 error_descriptions.append(description_with_path)
693 else:
694 warning_descriptions.append(description_with_path)
695
696 results = []
697 if error_descriptions:
698 results.append(output_api.PresubmitError(
699 'You added one or more #includes that violate checkdeps rules.',
700 error_descriptions))
701 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42702 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18703 'You added one or more #includes of files that are temporarily\n'
704 'allowed but being removed. Can you avoid introducing the\n'
705 '#include? See relevant DEPS file(s) for details and contacts.',
706 warning_descriptions))
707 return results
708
709
[email protected]fbcafe5a2012-08-08 15:31:22710def _CheckFilePermissions(input_api, output_api):
711 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15712 if input_api.platform == 'win32':
713 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29714 checkperms_tool = input_api.os_path.join(
715 input_api.PresubmitLocalPath(),
716 'tools', 'checkperms', 'checkperms.py')
717 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47718 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22719 for f in input_api.AffectedFiles():
720 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11721 try:
722 input_api.subprocess.check_output(args)
723 return []
724 except input_api.subprocess.CalledProcessError as error:
725 return [output_api.PresubmitError(
726 'checkperms.py failed:',
727 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22728
729
[email protected]c8278b32012-10-30 20:35:49730def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
731 """Makes sure we don't include ui/aura/window_property.h
732 in header files.
733 """
734 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
735 errors = []
736 for f in input_api.AffectedFiles():
737 if not f.LocalPath().endswith('.h'):
738 continue
739 for line_num, line in f.ChangedContents():
740 if pattern.match(line):
741 errors.append(' %s:%d' % (f.LocalPath(), line_num))
742
743 results = []
744 if errors:
745 results.append(output_api.PresubmitError(
746 'Header files should not include ui/aura/window_property.h', errors))
747 return results
748
749
[email protected]cf9b78f2012-11-14 11:40:28750def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
751 """Checks that the lines in scope occur in the right order.
752
753 1. C system files in alphabetical order
754 2. C++ system files in alphabetical order
755 3. Project's .h files
756 """
757
758 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
759 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
760 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
761
762 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
763
764 state = C_SYSTEM_INCLUDES
765
766 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57767 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28768 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55769 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28770 for line_num, line in scope:
771 if c_system_include_pattern.match(line):
772 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55773 problem_linenums.append((line_num, previous_line_num,
774 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28775 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55776 problem_linenums.append((line_num, previous_line_num,
777 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28778 elif cpp_system_include_pattern.match(line):
779 if state == C_SYSTEM_INCLUDES:
780 state = CPP_SYSTEM_INCLUDES
781 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55782 problem_linenums.append((line_num, previous_line_num,
783 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28784 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55785 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28786 elif custom_include_pattern.match(line):
787 if state != CUSTOM_INCLUDES:
788 state = CUSTOM_INCLUDES
789 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 else:
brucedawson70fadb02015-06-30 17:47:55792 problem_linenums.append((line_num, previous_line_num,
793 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28794 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57795 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28796
797 warnings = []
brucedawson70fadb02015-06-30 17:47:55798 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57799 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55800 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28801 return warnings
802
803
[email protected]ac294a12012-12-06 16:38:43804def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28805 """Checks the #include order for the given file f."""
806
[email protected]2299dcf2012-11-15 19:56:24807 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30808 # Exclude the following includes from the check:
809 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
810 # specific order.
811 # 2) <atlbase.h>, "build/build_config.h"
812 excluded_include_pattern = input_api.re.compile(
813 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24814 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33815 # Match the final or penultimate token if it is xxxtest so we can ignore it
816 # when considering the special first include.
817 test_file_tag_pattern = input_api.re.compile(
818 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11819 if_pattern = input_api.re.compile(
820 r'\s*#\s*(if|elif|else|endif|define|undef).*')
821 # Some files need specialized order of includes; exclude such files from this
822 # check.
823 uncheckable_includes_pattern = input_api.re.compile(
824 r'\s*#include '
825 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28826
827 contents = f.NewContents()
828 warnings = []
829 line_num = 0
830
[email protected]ac294a12012-12-06 16:38:43831 # Handle the special first include. If the first include file is
832 # some/path/file.h, the corresponding including file can be some/path/file.cc,
833 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
834 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33835 # If the included file is some/path/file_platform.h the including file could
836 # also be some/path/file_xxxtest_platform.h.
837 including_file_base_name = test_file_tag_pattern.sub(
838 '', input_api.os_path.basename(f.LocalPath()))
839
[email protected]ac294a12012-12-06 16:38:43840 for line in contents:
841 line_num += 1
842 if system_include_pattern.match(line):
843 # No special first include -> process the line again along with normal
844 # includes.
845 line_num -= 1
846 break
847 match = custom_include_pattern.match(line)
848 if match:
849 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33850 header_basename = test_file_tag_pattern.sub(
851 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
852
853 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24854 # No special first include -> process the line again along with normal
855 # includes.
856 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43857 break
[email protected]cf9b78f2012-11-14 11:40:28858
859 # Split into scopes: Each region between #if and #endif is its own scope.
860 scopes = []
861 current_scope = []
862 for line in contents[line_num:]:
863 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11864 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54865 continue
[email protected]2309b0fa02012-11-16 12:18:27866 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28867 scopes.append(current_scope)
868 current_scope = []
[email protected]962f117e2012-11-22 18:11:56869 elif ((system_include_pattern.match(line) or
870 custom_include_pattern.match(line)) and
871 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28872 current_scope.append((line_num, line))
873 scopes.append(current_scope)
874
875 for scope in scopes:
876 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
877 changed_linenums))
878 return warnings
879
880
881def _CheckIncludeOrder(input_api, output_api):
882 """Checks that the #include order is correct.
883
884 1. The corresponding header for source files.
885 2. C system files in alphabetical order
886 3. C++ system files in alphabetical order
887 4. Project's .h files in alphabetical order
888
[email protected]ac294a12012-12-06 16:38:43889 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
890 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28891 """
[email protected]e120b012014-08-15 19:08:35892 def FileFilterIncludeOrder(affected_file):
893 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
894 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28895
896 warnings = []
[email protected]e120b012014-08-15 19:08:35897 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08898 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43899 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
900 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28901
902 results = []
903 if warnings:
[email protected]f7051d52013-04-02 18:31:42904 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53905 warnings))
[email protected]cf9b78f2012-11-14 11:40:28906 return results
907
908
[email protected]70ca77752012-11-20 03:45:03909def _CheckForVersionControlConflictsInFile(input_api, f):
910 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
911 errors = []
912 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23913 if f.LocalPath().endswith('.md'):
914 # First-level headers in markdown look a lot like version control
915 # conflict markers. http://daringfireball.net/projects/markdown/basics
916 continue
[email protected]70ca77752012-11-20 03:45:03917 if pattern.match(line):
918 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
919 return errors
920
921
922def _CheckForVersionControlConflicts(input_api, output_api):
923 """Usually this is not intentional and will cause a compile failure."""
924 errors = []
925 for f in input_api.AffectedFiles():
926 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
927
928 results = []
929 if errors:
930 results.append(output_api.PresubmitError(
931 'Version control conflict markers found, please resolve.', errors))
932 return results
933
934
[email protected]06e6d0ff2012-12-11 01:36:44935def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
936 def FilterFile(affected_file):
937 """Filter function for use with input_api.AffectedSourceFiles,
938 below. This filters out everything except non-test files from
939 top-level directories that generally speaking should not hard-code
940 service URLs (e.g. src/android_webview/, src/content/ and others).
941 """
942 return input_api.FilterSourceFile(
943 affected_file,
[email protected]78bb39d62012-12-11 15:11:56944 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44945 black_list=(_EXCLUDED_PATHS +
946 _TEST_CODE_EXCLUDED_PATHS +
947 input_api.DEFAULT_BLACK_LIST))
948
reillyi38965732015-11-16 18:27:33949 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
950 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46951 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
952 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44953 problems = [] # items are (filename, line_number, line)
954 for f in input_api.AffectedSourceFiles(FilterFile):
955 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46956 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44957 problems.append((f.LocalPath(), line_num, line))
958
959 if problems:
[email protected]f7051d52013-04-02 18:31:42960 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44961 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58962 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44963 [' %s:%d: %s' % (
964 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03965 else:
966 return []
[email protected]06e6d0ff2012-12-11 01:36:44967
968
[email protected]d2530012013-01-25 16:39:27969def _CheckNoAbbreviationInPngFileName(input_api, output_api):
970 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31971 The native_client_sdk directory is excluded because it has auto-generated PNG
972 files for documentation.
[email protected]d2530012013-01-25 16:39:27973 """
[email protected]d2530012013-01-25 16:39:27974 errors = []
binji0dcdf342014-12-12 18:32:31975 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
976 black_list = (r'^native_client_sdk[\\\/]',)
977 file_filter = lambda f: input_api.FilterSourceFile(
978 f, white_list=white_list, black_list=black_list)
979 for f in input_api.AffectedFiles(include_deletes=False,
980 file_filter=file_filter):
981 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27982
983 results = []
984 if errors:
985 results.append(output_api.PresubmitError(
986 'The name of PNG files should not have abbreviations. \n'
987 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
988 'Contact [email protected] if you have questions.', errors))
989 return results
990
991
[email protected]14a6131c2014-01-08 01:15:41992def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08993 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41994 a set of DEPS entries that we should look up.
995
996 For a directory (rather than a specific filename) we fake a path to
997 a specific filename by adding /DEPS. This is chosen as a file that
998 will seldom or never be subject to per-file include_rules.
999 """
[email protected]2b438d62013-11-14 17:54:141000 # We ignore deps entries on auto-generated directories.
1001 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081002
1003 # This pattern grabs the path without basename in the first
1004 # parentheses, and the basename (if present) in the second. It
1005 # relies on the simple heuristic that if there is a basename it will
1006 # be a header file ending in ".h".
1007 pattern = re.compile(
1008 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141009 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081010 for changed_line in changed_lines:
1011 m = pattern.match(changed_line)
1012 if m:
1013 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141014 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411015 if m.group(2):
1016 results.add('%s%s' % (path, m.group(2)))
1017 else:
1018 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081019 return results
1020
1021
[email protected]e871964c2013-05-13 14:14:551022def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1023 """When a dependency prefixed with + is added to a DEPS file, we
1024 want to make sure that the change is reviewed by an OWNER of the
1025 target file or directory, to avoid layering violations from being
1026 introduced. This check verifies that this happens.
1027 """
1028 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241029
1030 file_filter = lambda f: not input_api.re.match(
1031 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1032 for f in input_api.AffectedFiles(include_deletes=False,
1033 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551034 filename = input_api.os_path.basename(f.LocalPath())
1035 if filename == 'DEPS':
1036 changed_lines |= set(line.strip()
1037 for line_num, line
1038 in f.ChangedContents())
1039 if not changed_lines:
1040 return []
1041
[email protected]14a6131c2014-01-08 01:15:411042 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1043 changed_lines)
[email protected]e871964c2013-05-13 14:14:551044 if not virtual_depended_on_files:
1045 return []
1046
1047 if input_api.is_committing:
1048 if input_api.tbr:
1049 return [output_api.PresubmitNotifyResult(
1050 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271051 if input_api.dry_run:
1052 return [output_api.PresubmitNotifyResult(
1053 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551054 if not input_api.change.issue:
1055 return [output_api.PresubmitError(
1056 "DEPS approval by OWNERS check failed: this change has "
1057 "no Rietveld issue number, so we can't check it for approvals.")]
1058 output = output_api.PresubmitError
1059 else:
1060 output = output_api.PresubmitNotifyResult
1061
1062 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501063 owner_email, reviewers = (
1064 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1065 input_api,
1066 owners_db.email_regexp,
1067 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551068
1069 owner_email = owner_email or input_api.change.author_email
1070
[email protected]de4f7d22013-05-23 14:27:461071 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511072 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461073 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551074 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1075 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411076
1077 # We strip the /DEPS part that was added by
1078 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1079 # directory.
1080 def StripDeps(path):
1081 start_deps = path.rfind('/DEPS')
1082 if start_deps != -1:
1083 return path[:start_deps]
1084 else:
1085 return path
1086 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551087 for path in missing_files]
1088
1089 if unapproved_dependencies:
1090 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151091 output('You need LGTM from owners of depends-on paths in DEPS that were '
1092 'modified in this CL:\n %s' %
1093 '\n '.join(sorted(unapproved_dependencies)))]
1094 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1095 output_list.append(output(
1096 'Suggested missing target path OWNERS:\n %s' %
1097 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551098 return output_list
1099
1100 return []
1101
1102
[email protected]85218562013-11-22 07:41:401103def _CheckSpamLogging(input_api, output_api):
1104 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1105 black_list = (_EXCLUDED_PATHS +
1106 _TEST_CODE_EXCLUDED_PATHS +
1107 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501108 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191109 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481110 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461111 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121112 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1113 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581114 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161115 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031116 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151117 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1118 r"^chromecast[\\\/]",
1119 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311120 r"^components[\\\/]html_viewer[\\\/]"
1121 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461122 # TODO(peter): Remove this exception. https://crbug.com/534537
1123 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1124 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251125 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1126 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241127 r"^courgette[\\\/]courgette_minimal_tool\.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
dchenge07de812016-06-20 19:27:171393def _CheckIpcOwners(input_api, output_api):
1394 """Checks that affected files involving IPC have an IPC OWNERS rule.
1395
1396 Whether or not a file affects IPC is determined by a simple whitelist of
1397 filename patterns."""
1398 file_patterns = [
1399 '*_messages.cc',
1400 '*_messages*.h',
1401 '*_param_traits*.*',
1402 '*.mojom',
1403 '*_struct_traits*.*',
1404 '*_type_converter*.*',
1405 # Blink uses a different file naming convention
1406 '*StructTraits*.*',
1407 '*TypeConverter*.*',
1408 ]
1409
1410 # Dictionary mapping an OWNERS file path to Patterns.
1411 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1412 # rules ) to a PatternEntry.
1413 # PatternEntry is a dictionary with two keys:
1414 # - 'files': the files that are matched by this pattern
1415 # - 'rules': the per-file rules needed for this pattern
1416 # For example, if we expect OWNERS file to contain rules for *.mojom and
1417 # *_struct_traits*.*, Patterns might look like this:
1418 # {
1419 # '*.mojom': {
1420 # 'files': ...,
1421 # 'rules': [
1422 # 'per-file *.mojom=set noparent',
1423 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1424 # ],
1425 # },
1426 # '*_struct_traits*.*': {
1427 # 'files': ...,
1428 # 'rules': [
1429 # 'per-file *_struct_traits*.*=set noparent',
1430 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1431 # ],
1432 # },
1433 # }
1434 to_check = {}
1435
1436 # Iterate through the affected files to see what we actually need to check
1437 # for. We should only nag patch authors about per-file rules if a file in that
1438 # directory would match that pattern. If a directory only contains *.mojom
1439 # files and no *_messages*.h files, we should only nag about rules for
1440 # *.mojom files.
rockot51249332016-06-23 16:32:251441 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171442 for pattern in file_patterns:
1443 if input_api.fnmatch.fnmatch(
1444 input_api.os_path.basename(f.LocalPath()), pattern):
1445 owners_file = input_api.os_path.join(
1446 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1447 if owners_file not in to_check:
1448 to_check[owners_file] = {}
1449 if pattern not in to_check[owners_file]:
1450 to_check[owners_file][pattern] = {
1451 'files': [],
1452 'rules': [
1453 'per-file %s=set noparent' % pattern,
1454 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1455 ]
1456 }
1457 to_check[owners_file][pattern]['files'].append(f)
1458 break
1459
1460 # Now go through the OWNERS files we collected, filtering out rules that are
1461 # already present in that OWNERS file.
1462 for owners_file, patterns in to_check.iteritems():
1463 try:
1464 with file(owners_file) as f:
1465 lines = set(f.read().splitlines())
1466 for entry in patterns.itervalues():
1467 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1468 ]
1469 except IOError:
1470 # No OWNERS file, so all the rules are definitely missing.
1471 continue
1472
1473 # All the remaining lines weren't found in OWNERS files, so emit an error.
1474 errors = []
1475 for owners_file, patterns in to_check.iteritems():
1476 missing_lines = []
1477 files = []
1478 for pattern, entry in patterns.iteritems():
1479 missing_lines.extend(entry['rules'])
1480 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1481 if missing_lines:
1482 errors.append(
1483 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1484 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1485
1486 results = []
1487 if errors:
vabrf5ce3bf92016-07-11 14:52:411488 if input_api.is_committing:
1489 output = output_api.PresubmitError
1490 else:
1491 output = output_api.PresubmitPromptWarning
1492 results.append(output(
dchenge07de812016-06-20 19:27:171493 'Found changes to IPC files without a security OWNER!',
1494 long_text='\n\n'.join(errors)))
1495
1496 return results
1497
1498
dskiba88634f4e2015-08-14 23:03:291499def _CheckAndroidToastUsage(input_api, output_api):
1500 """Checks that code uses org.chromium.ui.widget.Toast instead of
1501 android.widget.Toast (Chromium Toast doesn't force hardware
1502 acceleration on low-end devices, saving memory).
1503 """
1504 toast_import_pattern = input_api.re.compile(
1505 r'^import android\.widget\.Toast;$')
1506
1507 errors = []
1508
1509 sources = lambda affected_file: input_api.FilterSourceFile(
1510 affected_file,
1511 black_list=(_EXCLUDED_PATHS +
1512 _TEST_CODE_EXCLUDED_PATHS +
1513 input_api.DEFAULT_BLACK_LIST +
1514 (r'^chromecast[\\\/].*',
1515 r'^remoting[\\\/].*')),
1516 white_list=(r'.*\.java$',))
1517
1518 for f in input_api.AffectedSourceFiles(sources):
1519 for line_num, line in f.ChangedContents():
1520 if toast_import_pattern.search(line):
1521 errors.append("%s:%d" % (f.LocalPath(), line_num))
1522
1523 results = []
1524
1525 if errors:
1526 results.append(output_api.PresubmitError(
1527 'android.widget.Toast usage is detected. Android toasts use hardware'
1528 ' acceleration, and can be\ncostly on low-end devices. Please use'
1529 ' org.chromium.ui.widget.Toast instead.\n'
1530 'Contact [email protected] if you have any questions.',
1531 errors))
1532
1533 return results
1534
1535
dgnaa68d5e2015-06-10 10:08:221536def _CheckAndroidCrLogUsage(input_api, output_api):
1537 """Checks that new logs using org.chromium.base.Log:
1538 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511539 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221540 """
pkotwicza1dd0b002016-05-16 14:41:041541
1542 # Do not check format of logs in //chrome/android/webapk because
1543 # //chrome/android/webapk cannot depend on //base
1544 cr_log_check_excluded_paths = [
1545 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1546 ]
1547
dgnaa68d5e2015-06-10 10:08:221548 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121549 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1550 class_in_base_pattern = input_api.re.compile(
1551 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1552 has_some_log_import_pattern = input_api.re.compile(
1553 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221554 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121555 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221556 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511557 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221558 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221559
Vincent Scheib16d7b272015-09-15 18:09:071560 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221561 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041562 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1563 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121564
dgnaa68d5e2015-06-10 10:08:221565 tag_decl_errors = []
1566 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121567 tag_errors = []
dgn38736db2015-09-18 19:20:511568 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121569 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221570
1571 for f in input_api.AffectedSourceFiles(sources):
1572 file_content = input_api.ReadFile(f)
1573 has_modified_logs = False
1574
1575 # Per line checks
dgn87d9fb62015-06-12 09:15:121576 if (cr_log_import_pattern.search(file_content) or
1577 (class_in_base_pattern.search(file_content) and
1578 not has_some_log_import_pattern.search(file_content))):
1579 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221580 for line_num, line in f.ChangedContents():
1581
1582 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121583 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221584 if match:
1585 has_modified_logs = True
1586
1587 # Make sure it uses "TAG"
1588 if not match.group('tag') == 'TAG':
1589 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121590 else:
1591 # Report non cr Log function calls in changed lines
1592 for line_num, line in f.ChangedContents():
1593 if log_call_pattern.search(line):
1594 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221595
1596 # Per file checks
1597 if has_modified_logs:
1598 # Make sure the tag is using the "cr" prefix and is not too long
1599 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511600 tag_name = match.group('name') if match else None
1601 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221602 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511603 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221604 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511605 elif '.' in tag_name:
1606 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221607
1608 results = []
1609 if tag_decl_errors:
1610 results.append(output_api.PresubmitPromptWarning(
1611 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511612 '"private static final String TAG = "<package tag>".\n'
1613 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221614 tag_decl_errors))
1615
1616 if tag_length_errors:
1617 results.append(output_api.PresubmitError(
1618 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511619 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221620 tag_length_errors))
1621
1622 if tag_errors:
1623 results.append(output_api.PresubmitPromptWarning(
1624 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1625 tag_errors))
1626
dgn87d9fb62015-06-12 09:15:121627 if util_log_errors:
dgn4401aa52015-04-29 16:26:171628 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121629 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1630 util_log_errors))
1631
dgn38736db2015-09-18 19:20:511632 if tag_with_dot_errors:
1633 results.append(output_api.PresubmitPromptWarning(
1634 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1635 tag_with_dot_errors))
1636
dgn4401aa52015-04-29 16:26:171637 return results
1638
1639
agrieve7b6479d82015-10-07 14:24:221640def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1641 """Checks if MDPI assets are placed in a correct directory."""
1642 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1643 ('/res/drawable/' in f.LocalPath() or
1644 '/res/drawable-ldrtl/' in f.LocalPath()))
1645 errors = []
1646 for f in input_api.AffectedFiles(include_deletes=False,
1647 file_filter=file_filter):
1648 errors.append(' %s' % f.LocalPath())
1649
1650 results = []
1651 if errors:
1652 results.append(output_api.PresubmitError(
1653 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1654 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1655 '/res/drawable-ldrtl/.\n'
1656 'Contact [email protected] if you have questions.', errors))
1657 return results
1658
1659
agrievef32bcc72016-04-04 14:57:401660class PydepsChecker(object):
1661 def __init__(self, input_api, pydeps_files):
1662 self._file_cache = {}
1663 self._input_api = input_api
1664 self._pydeps_files = pydeps_files
1665
1666 def _LoadFile(self, path):
1667 """Returns the list of paths within a .pydeps file relative to //."""
1668 if path not in self._file_cache:
1669 with open(path) as f:
1670 self._file_cache[path] = f.read()
1671 return self._file_cache[path]
1672
1673 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1674 """Returns an interable of paths within the .pydep, relativized to //."""
1675 os_path = self._input_api.os_path
1676 pydeps_dir = os_path.dirname(pydeps_path)
1677 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1678 if not l.startswith('*'))
1679 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1680
1681 def _CreateFilesToPydepsMap(self):
1682 """Returns a map of local_path -> list_of_pydeps."""
1683 ret = {}
1684 for pydep_local_path in self._pydeps_files:
1685 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1686 ret.setdefault(path, []).append(pydep_local_path)
1687 return ret
1688
1689 def ComputeAffectedPydeps(self):
1690 """Returns an iterable of .pydeps files that might need regenerating."""
1691 affected_pydeps = set()
1692 file_to_pydeps_map = None
1693 for f in self._input_api.AffectedFiles(include_deletes=True):
1694 local_path = f.LocalPath()
1695 if local_path == 'DEPS':
1696 return self._pydeps_files
1697 elif local_path.endswith('.pydeps'):
1698 if local_path in self._pydeps_files:
1699 affected_pydeps.add(local_path)
1700 elif local_path.endswith('.py'):
1701 if file_to_pydeps_map is None:
1702 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1703 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1704 return affected_pydeps
1705
1706 def DetermineIfStale(self, pydeps_path):
1707 """Runs print_python_deps.py to see if the files is stale."""
1708 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1709 cmd = old_pydeps_data[1][1:].strip()
1710 new_pydeps_data = self._input_api.subprocess.check_output(
1711 cmd + ' --output ""', shell=True)
1712 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1713 return cmd
1714
1715
1716def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1717 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001718 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281719 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1720 # Mac, so skip it on other platforms.
1721 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001722 return []
agrievef32bcc72016-04-04 14:57:401723 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1724 is_android = input_api.os_path.exists('third_party/android_tools')
1725 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1726 results = []
1727 # First, check for new / deleted .pydeps.
1728 for f in input_api.AffectedFiles(include_deletes=True):
1729 if f.LocalPath().endswith('.pydeps'):
1730 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1731 results.append(output_api.PresubmitError(
1732 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1733 'remove %s' % f.LocalPath()))
1734 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1735 results.append(output_api.PresubmitError(
1736 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1737 'include %s' % f.LocalPath()))
1738
1739 if results:
1740 return results
1741
1742 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1743
1744 for pydep_path in checker.ComputeAffectedPydeps():
1745 try:
1746 cmd = checker.DetermineIfStale(pydep_path)
1747 if cmd:
1748 results.append(output_api.PresubmitError(
1749 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1750 (pydep_path, cmd)))
1751 except input_api.subprocess.CalledProcessError as error:
1752 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1753 long_text=error.output)]
1754
1755 return results
1756
1757
mnaganov9b9b1fe82014-12-11 16:30:361758def _CheckForCopyrightedCode(input_api, output_api):
1759 """Verifies that newly added code doesn't contain copyrighted material
1760 and is properly licensed under the standard Chromium license.
1761
1762 As there can be false positives, we maintain a whitelist file. This check
1763 also verifies that the whitelist file is up to date.
1764 """
1765 import sys
1766 original_sys_path = sys.path
1767 try:
1768 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221769 input_api.PresubmitLocalPath(), 'tools')]
1770 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361771 finally:
1772 # Restore sys.path to what it was before.
1773 sys.path = original_sys_path
1774
1775 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1776
1777
glidere61efad2015-02-18 17:39:431778def _CheckSingletonInHeaders(input_api, output_api):
1779 """Checks to make sure no header files have |Singleton<|."""
1780 def FileFilter(affected_file):
1781 # It's ok for base/memory/singleton.h to have |Singleton<|.
1782 black_list = (_EXCLUDED_PATHS +
1783 input_api.DEFAULT_BLACK_LIST +
1784 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1785 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1786
sergeyu34d21222015-09-16 00:11:441787 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431788 files = []
1789 for f in input_api.AffectedSourceFiles(FileFilter):
1790 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1791 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1792 contents = input_api.ReadFile(f)
1793 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241794 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431795 pattern.search(line)):
1796 files.append(f)
1797 break
1798
1799 if files:
yolandyandaabc6d2016-04-18 18:29:391800 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441801 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431802 'Please move them to an appropriate source file so that the ' +
1803 'template gets instantiated in a single compilation unit.',
1804 files) ]
1805 return []
1806
1807
dbeam37e8e7402016-02-10 22:58:201808def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1809 """Checks for old style compiled_resources.gyp files."""
1810 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1811
1812 added_compiled_resources = filter(is_compiled_resource, [
1813 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1814 ])
1815
1816 if not added_compiled_resources:
1817 return []
1818
1819 return [output_api.PresubmitError(
1820 "Found new compiled_resources.gyp files:\n%s\n\n"
1821 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551822 "please use compiled_resources2.gyp instead:\n"
1823 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1824 %
dbeam37e8e7402016-02-10 22:58:201825 "\n".join(added_compiled_resources))]
1826
1827
[email protected]fd20b902014-05-09 02:14:531828_DEPRECATED_CSS = [
1829 # Values
1830 ( "-webkit-box", "flex" ),
1831 ( "-webkit-inline-box", "inline-flex" ),
1832 ( "-webkit-flex", "flex" ),
1833 ( "-webkit-inline-flex", "inline-flex" ),
1834 ( "-webkit-min-content", "min-content" ),
1835 ( "-webkit-max-content", "max-content" ),
1836
1837 # Properties
1838 ( "-webkit-background-clip", "background-clip" ),
1839 ( "-webkit-background-origin", "background-origin" ),
1840 ( "-webkit-background-size", "background-size" ),
1841 ( "-webkit-box-shadow", "box-shadow" ),
1842
1843 # Functions
1844 ( "-webkit-gradient", "gradient" ),
1845 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1846 ( "-webkit-linear-gradient", "linear-gradient" ),
1847 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1848 ( "-webkit-radial-gradient", "radial-gradient" ),
1849 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1850]
1851
1852def _CheckNoDeprecatedCSS(input_api, output_api):
1853 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251854 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341855 documentation and iOS CSS for dom distiller
1856 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251857 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531858 results = []
dbeam070cfe62014-10-22 06:44:021859 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251860 black_list = (_EXCLUDED_PATHS +
1861 _TEST_CODE_EXCLUDED_PATHS +
1862 input_api.DEFAULT_BLACK_LIST +
1863 (r"^chrome/common/extensions/docs",
1864 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341865 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051866 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441867 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251868 r"^native_client_sdk"))
1869 file_filter = lambda f: input_api.FilterSourceFile(
1870 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531871 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1872 for line_num, line in fpath.ChangedContents():
1873 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021874 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531875 results.append(output_api.PresubmitError(
1876 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1877 (fpath.LocalPath(), line_num, deprecated_value, value)))
1878 return results
1879
mohan.reddyf21db962014-10-16 12:26:471880
dbeam070cfe62014-10-22 06:44:021881_DEPRECATED_JS = [
1882 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1883 ( "__defineGetter__", "Object.defineProperty" ),
1884 ( "__defineSetter__", "Object.defineProperty" ),
1885]
1886
1887def _CheckNoDeprecatedJS(input_api, output_api):
1888 """Make sure that we don't use deprecated JS in Chrome code."""
1889 results = []
1890 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1891 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1892 input_api.DEFAULT_BLACK_LIST)
1893 file_filter = lambda f: input_api.FilterSourceFile(
1894 f, white_list=file_inclusion_pattern, black_list=black_list)
1895 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1896 for lnum, line in fpath.ChangedContents():
1897 for (deprecated, replacement) in _DEPRECATED_JS:
1898 if deprecated in line:
1899 results.append(output_api.PresubmitError(
1900 "%s:%d: Use of deprecated JS %s, use %s instead" %
1901 (fpath.LocalPath(), lnum, deprecated, replacement)))
1902 return results
1903
1904
dgnaa68d5e2015-06-10 10:08:221905def _AndroidSpecificOnUploadChecks(input_api, output_api):
1906 """Groups checks that target android code."""
1907 results = []
dgnaa68d5e2015-06-10 10:08:221908 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221909 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291910 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221911 return results
1912
1913
[email protected]22c9bd72011-03-27 16:47:391914def _CommonChecks(input_api, output_api):
1915 """Checks common to both upload and commit."""
1916 results = []
1917 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381918 input_api, output_api,
1919 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461920 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191921 results.extend(
[email protected]760deea2013-12-10 19:33:491922 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541923 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181924 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521925 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221926 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441927 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591928 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061929 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121930 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181931 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221932 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491933 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271934 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031935 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491936 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441937 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271938 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541939 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441940 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391941 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551942 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041943 results.extend(
1944 input_api.canned_checks.CheckChangeHasNoTabs(
1945 input_api,
1946 output_api,
1947 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401948 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161949 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591950 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081951 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531952 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021953 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471954 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041955 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361956 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231957 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431958 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201959 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401960 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:151961 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:171962 results.extend(_CheckIpcOwners(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241963
1964 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1965 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1966 input_api, output_api,
1967 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381968 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391969 return results
[email protected]1f7b4172010-01-28 01:17:341970
[email protected]b337cb5b2011-01-23 21:24:051971
[email protected]66daa702011-05-28 14:41:461972def _CheckAuthorizedAuthor(input_api, output_api):
1973 """For non-googler/chromites committers, verify the author's email address is
1974 in AUTHORS.
1975 """
1976 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011977 if not author:
1978 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461979 return []
[email protected]c99663292011-05-31 19:46:081980 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461981 input_api.PresubmitLocalPath(), 'AUTHORS')
1982 valid_authors = (
1983 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1984 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181985 valid_authors = [item.group(1).lower() for item in valid_authors if item]
dchenge07de812016-06-20 19:27:171986 if not any(input_api.fnmatch.fnmatch(author.lower(), valid)
1987 for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231988 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461989 return [output_api.PresubmitPromptWarning(
1990 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1991 '\n'
1992 'http://www.chromium.org/developers/contributing-code and read the '
1993 '"Legal" section\n'
1994 'If you are a chromite, verify the contributor signed the CLA.') %
1995 author)]
1996 return []
1997
1998
[email protected]b8079ae4a2012-12-05 19:56:491999def _CheckPatchFiles(input_api, output_api):
2000 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2001 if f.LocalPath().endswith(('.orig', '.rej'))]
2002 if problems:
2003 return [output_api.PresubmitError(
2004 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032005 else:
2006 return []
[email protected]b8079ae4a2012-12-05 19:56:492007
2008
[email protected]b00342e7f2013-03-26 16:21:542009def _DidYouMeanOSMacro(bad_macro):
2010 try:
2011 return {'A': 'OS_ANDROID',
2012 'B': 'OS_BSD',
2013 'C': 'OS_CHROMEOS',
2014 'F': 'OS_FREEBSD',
2015 'L': 'OS_LINUX',
2016 'M': 'OS_MACOSX',
2017 'N': 'OS_NACL',
2018 'O': 'OS_OPENBSD',
2019 'P': 'OS_POSIX',
2020 'S': 'OS_SOLARIS',
2021 'W': 'OS_WIN'}[bad_macro[3].upper()]
2022 except KeyError:
2023 return ''
2024
2025
2026def _CheckForInvalidOSMacrosInFile(input_api, f):
2027 """Check for sensible looking, totally invalid OS macros."""
2028 preprocessor_statement = input_api.re.compile(r'^\s*#')
2029 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2030 results = []
2031 for lnum, line in f.ChangedContents():
2032 if preprocessor_statement.search(line):
2033 for match in os_macro.finditer(line):
2034 if not match.group(1) in _VALID_OS_MACROS:
2035 good = _DidYouMeanOSMacro(match.group(1))
2036 did_you_mean = ' (did you mean %s?)' % good if good else ''
2037 results.append(' %s:%d %s%s' % (f.LocalPath(),
2038 lnum,
2039 match.group(1),
2040 did_you_mean))
2041 return results
2042
2043
2044def _CheckForInvalidOSMacros(input_api, output_api):
2045 """Check all affected files for invalid OS macros."""
2046 bad_macros = []
2047 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472048 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542049 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2050
2051 if not bad_macros:
2052 return []
2053
2054 return [output_api.PresubmitError(
2055 'Possibly invalid OS macro[s] found. Please fix your code\n'
2056 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2057
lliabraa35bab3932014-10-01 12:16:442058
2059def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2060 """Check all affected files for invalid "if defined" macros."""
2061 ALWAYS_DEFINED_MACROS = (
2062 "TARGET_CPU_PPC",
2063 "TARGET_CPU_PPC64",
2064 "TARGET_CPU_68K",
2065 "TARGET_CPU_X86",
2066 "TARGET_CPU_ARM",
2067 "TARGET_CPU_MIPS",
2068 "TARGET_CPU_SPARC",
2069 "TARGET_CPU_ALPHA",
2070 "TARGET_IPHONE_SIMULATOR",
2071 "TARGET_OS_EMBEDDED",
2072 "TARGET_OS_IPHONE",
2073 "TARGET_OS_MAC",
2074 "TARGET_OS_UNIX",
2075 "TARGET_OS_WIN32",
2076 )
2077 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2078 results = []
2079 for lnum, line in f.ChangedContents():
2080 for match in ifdef_macro.finditer(line):
2081 if match.group(1) in ALWAYS_DEFINED_MACROS:
2082 always_defined = ' %s is always defined. ' % match.group(1)
2083 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2084 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2085 lnum,
2086 always_defined,
2087 did_you_mean))
2088 return results
2089
2090
2091def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2092 """Check all affected files for invalid "if defined" macros."""
2093 bad_macros = []
2094 for f in input_api.AffectedFiles():
2095 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2096 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2097
2098 if not bad_macros:
2099 return []
2100
2101 return [output_api.PresubmitError(
2102 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2103 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2104 bad_macros)]
2105
2106
mlamouria82272622014-09-16 18:45:042107def _CheckForIPCRules(input_api, output_api):
2108 """Check for same IPC rules described in
2109 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2110 """
2111 base_pattern = r'IPC_ENUM_TRAITS\('
2112 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2113 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2114
2115 problems = []
2116 for f in input_api.AffectedSourceFiles(None):
2117 local_path = f.LocalPath()
2118 if not local_path.endswith('.h'):
2119 continue
2120 for line_number, line in f.ChangedContents():
2121 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2122 problems.append(
2123 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2124
2125 if problems:
2126 return [output_api.PresubmitPromptWarning(
2127 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2128 else:
2129 return []
2130
[email protected]b00342e7f2013-03-26 16:21:542131
mostynbb639aca52015-01-07 20:31:232132def _CheckForWindowsLineEndings(input_api, output_api):
2133 """Check source code and known ascii text files for Windows style line
2134 endings.
2135 """
earthdok1b5e0ee2015-03-10 15:19:102136 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232137
2138 file_inclusion_pattern = (
2139 known_text_files,
2140 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2141 )
2142
2143 filter = lambda f: input_api.FilterSourceFile(
2144 f, white_list=file_inclusion_pattern, black_list=None)
2145 files = [f.LocalPath() for f in
2146 input_api.AffectedSourceFiles(filter)]
2147
2148 problems = []
2149
2150 for file in files:
2151 fp = open(file, 'r')
2152 for line in fp:
2153 if line.endswith('\r\n'):
2154 problems.append(file)
2155 break
2156 fp.close()
2157
2158 if problems:
2159 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2160 'these files to contain Windows style line endings?\n' +
2161 '\n'.join(problems))]
2162
2163 return []
2164
2165
[email protected]1f7b4172010-01-28 01:17:342166def CheckChangeOnUpload(input_api, output_api):
2167 results = []
2168 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472169 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282170 results.extend(
2171 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192172 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222173 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542174 return results
[email protected]ca8d19842009-02-19 16:33:122175
2176
[email protected]1bfb8322014-04-23 01:02:412177def GetTryServerMasterForBot(bot):
2178 """Returns the Try Server master for the given bot.
2179
[email protected]0bb112362014-07-26 04:38:322180 It tries to guess the master from the bot name, but may still fail
2181 and return None. There is no longer a default master.
2182 """
2183 # Potentially ambiguous bot names are listed explicitly.
2184 master_map = {
[email protected]0bb112362014-07-26 04:38:322185 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322186 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412187 }
[email protected]0bb112362014-07-26 04:38:322188 master = master_map.get(bot)
2189 if not master:
wnwen4fbaab82016-05-25 12:54:362190 if 'android' in bot:
2191 master = 'tryserver.chromium.android'
2192 elif 'linux' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322193 master = 'tryserver.chromium.linux'
2194 elif 'win' in bot:
2195 master = 'tryserver.chromium.win'
2196 elif 'mac' in bot or 'ios' in bot:
2197 master = 'tryserver.chromium.mac'
2198 return master
[email protected]1bfb8322014-04-23 01:02:412199
2200
Paweł Hajdan, Jr55083782014-12-19 20:32:562201def GetDefaultTryConfigs(bots):
2202 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012203 """
2204
Paweł Hajdan, Jr55083782014-12-19 20:32:562205 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412206
2207 # Build up the mapping from tryserver master to bot/test.
2208 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562209 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412210 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2211 return out
[email protected]38c6a512013-12-18 23:48:012212
2213
[email protected]ca8d19842009-02-19 16:33:122214def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542215 results = []
[email protected]1f7b4172010-01-28 01:17:342216 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542217 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272218 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342219 input_api,
2220 output_api,
[email protected]2fdd1f362013-01-16 03:56:032221 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272222
[email protected]3e4eb112011-01-18 03:29:542223 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2224 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412225 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2226 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542227 return results