blob: 34fb5e6c23e56842094019b4c549c96e61d23cc7 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
[email protected]4306417642009-06-11 00:33:4028)
[email protected]ca8d1982009-02-19 16:33:1229
wnwenbdc444e2016-05-25 13:44:1530
[email protected]06e6d0ff2012-12-11 01:36:4431# Fragment of a regular expression that matches C++ and Objective-C++
32# implementation files.
33_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
34
wnwenbdc444e2016-05-25 13:44:1535
[email protected]06e6d0ff2012-12-11 01:36:4436# Regular expression that matches code only used for test binaries
37# (best effort).
38_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4939 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4440 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5341 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1242 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4944 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0545 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4946 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4747 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4948 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0849 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4950 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4451)
[email protected]ca8d1982009-02-19 16:33:1252
wnwenbdc444e2016-05-25 13:44:1553
[email protected]eea609a2011-11-18 13:10:1254_TEST_ONLY_WARNING = (
55 'You might be calling functions intended only for testing from\n'
56 'production code. It is OK to ignore this warning if you know what\n'
57 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5858 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1259
60
[email protected]cf9b78f2012-11-14 11:40:2861_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4062 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2163 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
64 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2865
wnwenbdc444e2016-05-25 13:44:1566
[email protected]127f18ec2012-06-16 05:05:5967_BANNED_OBJC_FUNCTIONS = (
68 (
69 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2070 (
71 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5972 'prohibited. Please use CrTrackingArea instead.',
73 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
74 ),
75 False,
76 ),
77 (
[email protected]eaae1972014-04-16 04:17:2678 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2079 (
80 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5981 'instead.',
82 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
83 ),
84 False,
85 ),
86 (
87 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2088 (
89 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5990 'Please use |convertPoint:(point) fromView:nil| instead.',
91 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
92 ),
93 True,
94 ),
95 (
96 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5999 'Please use |convertPoint:(point) toView:nil| instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 True,
103 ),
104 (
105 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59108 'Please use |convertRect:(point) fromView:nil| instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 True,
112 ),
113 (
114 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertRect:(point) toView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertSize:(point) fromView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertSize:(point) toView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
jif65398702016-10-27 10:19:48140 (
141 r"/\s+UTF8String\s*]",
142 (
143 'The use of -[NSString UTF8String] is dangerous as it can return null',
144 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
145 'Please use |SysNSStringToUTF8| instead.',
146 ),
147 True,
148 ),
[email protected]127f18ec2012-06-16 05:05:59149)
150
151
152_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20153 # Make sure that gtest's FRIEND_TEST() macro is not used; the
154 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30155 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20156 (
157 'FRIEND_TEST(',
158 (
[email protected]e3c945502012-06-26 20:01:49159 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20160 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
161 ),
162 False,
[email protected]7345da02012-11-27 14:31:49163 (),
[email protected]23e6cbc2012-06-16 18:51:20164 ),
165 (
thomasanderson4b569052016-09-14 20:15:53166 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
167 (
168 'Chrome clients wishing to select events on X windows should use',
169 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
170 'you are selecting events from the GPU process, or if you are using',
171 'an XDisplay other than gfx::GetXDisplay().',
172 ),
173 True,
174 (
175 r"^ui[\\\/]gl[\\\/].*\.cc$",
176 r"^media[\\\/]gpu[\\\/].*\.cc$",
177 r"^gpu[\\\/].*\.cc$",
178 ),
179 ),
180 (
[email protected]23e6cbc2012-06-16 18:51:20181 'ScopedAllowIO',
182 (
[email protected]e3c945502012-06-26 20:01:49183 'New code should not use ScopedAllowIO. Post a task to the blocking',
184 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20185 ),
[email protected]e3c945502012-06-26 20:01:49186 True,
[email protected]7345da02012-11-27 14:31:49187 (
nyad2c548b2015-12-09 03:22:32188 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10189 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22190 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31191 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51192 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
193 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09194 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49195 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
196 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25197 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41198 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
199 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25200 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48201 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
202 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01203 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25204 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
205 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
206 r"embedded_test_server\.cc$",
207 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
208 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54209 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16210 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53211 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
212 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45213 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
214 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
215 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
216 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
217 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49218 ),
[email protected]23e6cbc2012-06-16 18:51:20219 ),
[email protected]52657f62013-05-20 05:30:31220 (
tomhudsone2c14d552016-05-26 17:07:46221 'setMatrixClip',
222 (
223 'Overriding setMatrixClip() is prohibited; ',
224 'the base function is deprecated. ',
225 ),
226 True,
227 (),
228 ),
229 (
[email protected]52657f62013-05-20 05:30:31230 'SkRefPtr',
231 (
232 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22233 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31234 ),
235 True,
236 (),
237 ),
238 (
239 'SkAutoRef',
240 (
241 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22242 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31243 ),
244 True,
245 (),
246 ),
247 (
248 'SkAutoTUnref',
249 (
250 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22251 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31252 ),
253 True,
254 (),
255 ),
256 (
257 'SkAutoUnref',
258 (
259 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
260 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22261 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31262 ),
263 True,
264 (),
265 ),
[email protected]d89eec82013-12-03 14:10:59266 (
267 r'/HANDLE_EINTR\(.*close',
268 (
269 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
270 'descriptor will be closed, and it is incorrect to retry the close.',
271 'Either call close directly and ignore its return value, or wrap close',
272 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
273 ),
274 True,
275 (),
276 ),
277 (
278 r'/IGNORE_EINTR\((?!.*close)',
279 (
280 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
281 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
282 ),
283 True,
284 (
285 # Files that #define IGNORE_EINTR.
286 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
287 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
288 ),
289 ),
[email protected]ec5b3f02014-04-04 18:43:43290 (
291 r'/v8::Extension\(',
292 (
293 'Do not introduce new v8::Extensions into the code base, use',
294 'gin::Wrappable instead. See http://crbug.com/334679',
295 ),
296 True,
[email protected]f55c90ee62014-04-12 00:50:03297 (
joaodasilva718f87672014-08-30 09:25:49298 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03299 ),
[email protected]ec5b3f02014-04-04 18:43:43300 ),
skyostilf9469f72015-04-20 10:38:52301 (
jame2d1a952016-04-02 00:27:10302 '#pragma comment(lib,',
303 (
304 'Specify libraries to link with in build files and not in the source.',
305 ),
306 True,
307 (),
308 ),
[email protected]127f18ec2012-06-16 05:05:59309)
310
wnwenbdc444e2016-05-25 13:44:15311
mlamouria82272622014-09-16 18:45:04312_IPC_ENUM_TRAITS_DEPRECATED = (
313 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
314 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
315
[email protected]127f18ec2012-06-16 05:05:59316
[email protected]b00342e7f2013-03-26 16:21:54317_VALID_OS_MACROS = (
318 # Please keep sorted.
319 'OS_ANDROID',
320 'OS_BSD',
321 'OS_CAT', # For testing.
322 'OS_CHROMEOS',
323 'OS_FREEBSD',
324 'OS_IOS',
325 'OS_LINUX',
326 'OS_MACOSX',
327 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21328 'OS_NACL_NONSFI',
329 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12330 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54331 'OS_OPENBSD',
332 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37333 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54334 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54335 'OS_WIN',
336)
337
338
agrievef32bcc72016-04-04 14:57:40339_ANDROID_SPECIFIC_PYDEPS_FILES = [
340 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19341 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40342]
343
wnwenbdc444e2016-05-25 13:44:15344
agrievef32bcc72016-04-04 14:57:40345_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40346]
347
wnwenbdc444e2016-05-25 13:44:15348
agrievef32bcc72016-04-04 14:57:40349_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
350
351
[email protected]55459852011-08-10 15:17:19352def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
353 """Attempts to prevent use of functions intended only for testing in
354 non-testing code. For now this is just a best-effort implementation
355 that ignores header files and may have some false positives. A
356 better implementation would probably need a proper C++ parser.
357 """
358 # We only scan .cc files and the like, as the declaration of
359 # for-testing functions in header files are hard to distinguish from
360 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44361 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19362
jochenc0d4808c2015-07-27 09:25:42363 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19364 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09365 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19366 exclusion_pattern = input_api.re.compile(
367 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
368 base_function_pattern, base_function_pattern))
369
370 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44371 black_list = (_EXCLUDED_PATHS +
372 _TEST_CODE_EXCLUDED_PATHS +
373 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19374 return input_api.FilterSourceFile(
375 affected_file,
376 white_list=(file_inclusion_pattern, ),
377 black_list=black_list)
378
379 problems = []
380 for f in input_api.AffectedSourceFiles(FilterFile):
381 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24382 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03383 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46384 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03385 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19386 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03387 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19388
389 if problems:
[email protected]f7051d52013-04-02 18:31:42390 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03391 else:
392 return []
[email protected]55459852011-08-10 15:17:19393
394
[email protected]10689ca2011-09-02 02:31:54395def _CheckNoIOStreamInHeaders(input_api, output_api):
396 """Checks to make sure no .h files include <iostream>."""
397 files = []
398 pattern = input_api.re.compile(r'^#include\s*<iostream>',
399 input_api.re.MULTILINE)
400 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
401 if not f.LocalPath().endswith('.h'):
402 continue
403 contents = input_api.ReadFile(f)
404 if pattern.search(contents):
405 files.append(f)
406
407 if len(files):
yolandyandaabc6d2016-04-18 18:29:39408 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06409 'Do not #include <iostream> in header files, since it inserts static '
410 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54411 '#include <ostream>. See http://crbug.com/94794',
412 files) ]
413 return []
414
415
[email protected]72df4e782012-06-21 16:28:18416def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52417 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18418 problems = []
419 for f in input_api.AffectedFiles():
420 if (not f.LocalPath().endswith(('.cc', '.mm'))):
421 continue
422
423 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04424 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18425 problems.append(' %s:%d' % (f.LocalPath(), line_num))
426
427 if not problems:
428 return []
429 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
430 '\n'.join(problems))]
431
432
danakj61c1aa22015-10-26 19:55:52433def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
434 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
435 errors = []
436 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
437 input_api.re.MULTILINE)
438 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
439 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
440 continue
441 for lnum, line in f.ChangedContents():
442 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17443 errors.append(output_api.PresubmitError(
444 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
445 'DCHECK_IS_ON()", not forgetting the braces.')
446 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52447 return errors
448
449
mcasasb7440c282015-02-04 14:52:19450def _FindHistogramNameInLine(histogram_name, line):
451 """Tries to find a histogram name or prefix in a line."""
452 if not "affected-histogram" in line:
453 return histogram_name in line
454 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
455 # the histogram_name.
456 if not '"' in line:
457 return False
458 histogram_prefix = line.split('\"')[1]
459 return histogram_prefix in histogram_name
460
461
462def _CheckUmaHistogramChanges(input_api, output_api):
463 """Check that UMA histogram names in touched lines can still be found in other
464 lines of the patch or in histograms.xml. Note that this check would not catch
465 the reverse: changes in histograms.xml not matched in the code itself."""
466 touched_histograms = []
467 histograms_xml_modifications = []
468 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
469 for f in input_api.AffectedFiles():
470 # If histograms.xml itself is modified, keep the modified lines for later.
471 if f.LocalPath().endswith(('histograms.xml')):
472 histograms_xml_modifications = f.ChangedContents()
473 continue
474 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
475 continue
476 for line_num, line in f.ChangedContents():
477 found = pattern.search(line)
478 if found:
479 touched_histograms.append([found.group(1), f, line_num])
480
481 # Search for the touched histogram names in the local modifications to
482 # histograms.xml, and, if not found, on the base histograms.xml file.
483 unmatched_histograms = []
484 for histogram_info in touched_histograms:
485 histogram_name_found = False
486 for line_num, line in histograms_xml_modifications:
487 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
488 if histogram_name_found:
489 break
490 if not histogram_name_found:
491 unmatched_histograms.append(histogram_info)
492
eromanb90c82e7e32015-04-01 15:13:49493 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19494 problems = []
495 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49496 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19497 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45498 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19499 histogram_name_found = False
500 for line in histograms_xml:
501 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
502 if histogram_name_found:
503 break
504 if not histogram_name_found:
505 problems.append(' [%s:%d] %s' %
506 (f.LocalPath(), line_num, histogram_name))
507
508 if not problems:
509 return []
510 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
511 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49512 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19513
wnwenbdc444e2016-05-25 13:44:15514
yolandyandaabc6d2016-04-18 18:29:39515def _CheckFlakyTestUsage(input_api, output_api):
516 """Check that FlakyTest annotation is our own instead of the android one"""
517 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
518 files = []
519 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
520 if f.LocalPath().endswith('Test.java'):
521 if pattern.search(input_api.ReadFile(f)):
522 files.append(f)
523 if len(files):
524 return [output_api.PresubmitError(
525 'Use org.chromium.base.test.util.FlakyTest instead of '
526 'android.test.FlakyTest',
527 files)]
528 return []
mcasasb7440c282015-02-04 14:52:19529
wnwenbdc444e2016-05-25 13:44:15530
[email protected]8ea5d4b2011-09-13 21:49:22531def _CheckNoNewWStrings(input_api, output_api):
532 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27533 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22534 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20535 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57536 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34537 '/win/' in f.LocalPath() or
538 'chrome_elf' in f.LocalPath() or
539 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20540 continue
[email protected]8ea5d4b2011-09-13 21:49:22541
[email protected]a11dbe9b2012-08-07 01:32:58542 allowWString = False
[email protected]b5c24292011-11-28 14:38:20543 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58544 if 'presubmit: allow wstring' in line:
545 allowWString = True
546 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27547 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58548 allowWString = False
549 else:
550 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22551
[email protected]55463aa62011-10-12 00:48:27552 if not problems:
553 return []
554 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58555 ' If you are calling a cross-platform API that accepts a wstring, '
556 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27557 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22558
559
[email protected]2a8ac9c2011-10-19 17:20:44560def _CheckNoDEPSGIT(input_api, output_api):
561 """Make sure .DEPS.git is never modified manually."""
562 if any(f.LocalPath().endswith('.DEPS.git') for f in
563 input_api.AffectedFiles()):
564 return [output_api.PresubmitError(
565 'Never commit changes to .DEPS.git. This file is maintained by an\n'
566 'automated system based on what\'s in DEPS and your changes will be\n'
567 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34568 '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:44569 'for more information')]
570 return []
571
572
tandriief664692014-09-23 14:51:47573def _CheckValidHostsInDEPS(input_api, output_api):
574 """Checks that DEPS file deps are from allowed_hosts."""
575 # Run only if DEPS file has been modified to annoy fewer bystanders.
576 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
577 return []
578 # Outsource work to gclient verify
579 try:
580 input_api.subprocess.check_output(['gclient', 'verify'])
581 return []
582 except input_api.subprocess.CalledProcessError, error:
583 return [output_api.PresubmitError(
584 'DEPS file must have only git dependencies.',
585 long_text=error.output)]
586
587
[email protected]127f18ec2012-06-16 05:05:59588def _CheckNoBannedFunctions(input_api, output_api):
589 """Make sure that banned functions are not used."""
590 warnings = []
591 errors = []
592
wnwenbdc444e2016-05-25 13:44:15593 def IsBlacklisted(affected_file, blacklist):
594 local_path = affected_file.LocalPath()
595 for item in blacklist:
596 if input_api.re.match(item, local_path):
597 return True
598 return False
599
600 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
601 matched = False
602 if func_name[0:1] == '/':
603 regex = func_name[1:]
604 if input_api.re.search(regex, line):
605 matched = True
606 elif func_name in line:
dchenge07de812016-06-20 19:27:17607 matched = True
wnwenbdc444e2016-05-25 13:44:15608 if matched:
dchenge07de812016-06-20 19:27:17609 problems = warnings
wnwenbdc444e2016-05-25 13:44:15610 if error:
dchenge07de812016-06-20 19:27:17611 problems = errors
wnwenbdc444e2016-05-25 13:44:15612 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
613 for message_line in message:
614 problems.append(' %s' % message_line)
615
[email protected]127f18ec2012-06-16 05:05:59616 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
617 for f in input_api.AffectedFiles(file_filter=file_filter):
618 for line_num, line in f.ChangedContents():
619 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15620 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59621
622 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
623 for f in input_api.AffectedFiles(file_filter=file_filter):
624 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49625 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49626 if IsBlacklisted(f, excluded_paths):
627 continue
wnwenbdc444e2016-05-25 13:44:15628 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59629
630 result = []
631 if (warnings):
632 result.append(output_api.PresubmitPromptWarning(
633 'Banned functions were used.\n' + '\n'.join(warnings)))
634 if (errors):
635 result.append(output_api.PresubmitError(
636 'Banned functions were used.\n' + '\n'.join(errors)))
637 return result
638
639
[email protected]6c063c62012-07-11 19:11:06640def _CheckNoPragmaOnce(input_api, output_api):
641 """Make sure that banned functions are not used."""
642 files = []
643 pattern = input_api.re.compile(r'^#pragma\s+once',
644 input_api.re.MULTILINE)
645 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
646 if not f.LocalPath().endswith('.h'):
647 continue
648 contents = input_api.ReadFile(f)
649 if pattern.search(contents):
650 files.append(f)
651
652 if files:
653 return [output_api.PresubmitError(
654 'Do not use #pragma once in header files.\n'
655 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
656 files)]
657 return []
658
[email protected]127f18ec2012-06-16 05:05:59659
[email protected]e7479052012-09-19 00:26:12660def _CheckNoTrinaryTrueFalse(input_api, output_api):
661 """Checks to make sure we don't introduce use of foo ? true : false."""
662 problems = []
663 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
664 for f in input_api.AffectedFiles():
665 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
666 continue
667
668 for line_num, line in f.ChangedContents():
669 if pattern.match(line):
670 problems.append(' %s:%d' % (f.LocalPath(), line_num))
671
672 if not problems:
673 return []
674 return [output_api.PresubmitPromptWarning(
675 'Please consider avoiding the "? true : false" pattern if possible.\n' +
676 '\n'.join(problems))]
677
678
[email protected]55f9f382012-07-31 11:02:18679def _CheckUnwantedDependencies(input_api, output_api):
680 """Runs checkdeps on #include statements added in this
681 change. Breaking - rules is an error, breaking ! rules is a
682 warning.
683 """
mohan.reddyf21db962014-10-16 12:26:47684 import sys
[email protected]55f9f382012-07-31 11:02:18685 # We need to wait until we have an input_api object and use this
686 # roundabout construct to import checkdeps because this file is
687 # eval-ed and thus doesn't have __file__.
688 original_sys_path = sys.path
689 try:
690 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47691 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18692 import checkdeps
693 from cpp_checker import CppChecker
694 from rules import Rule
695 finally:
696 # Restore sys.path to what it was before.
697 sys.path = original_sys_path
698
699 added_includes = []
700 for f in input_api.AffectedFiles():
701 if not CppChecker.IsCppFile(f.LocalPath()):
702 continue
703
704 changed_lines = [line for line_num, line in f.ChangedContents()]
705 added_includes.append([f.LocalPath(), changed_lines])
706
[email protected]26385172013-05-09 23:11:35707 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18708
709 error_descriptions = []
710 warning_descriptions = []
711 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
712 added_includes):
713 description_with_path = '%s\n %s' % (path, rule_description)
714 if rule_type == Rule.DISALLOW:
715 error_descriptions.append(description_with_path)
716 else:
717 warning_descriptions.append(description_with_path)
718
719 results = []
720 if error_descriptions:
721 results.append(output_api.PresubmitError(
722 'You added one or more #includes that violate checkdeps rules.',
723 error_descriptions))
724 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42725 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18726 'You added one or more #includes of files that are temporarily\n'
727 'allowed but being removed. Can you avoid introducing the\n'
728 '#include? See relevant DEPS file(s) for details and contacts.',
729 warning_descriptions))
730 return results
731
732
[email protected]fbcafe5a2012-08-08 15:31:22733def _CheckFilePermissions(input_api, output_api):
734 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15735 if input_api.platform == 'win32':
736 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29737 checkperms_tool = input_api.os_path.join(
738 input_api.PresubmitLocalPath(),
739 'tools', 'checkperms', 'checkperms.py')
740 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47741 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22742 for f in input_api.AffectedFiles():
743 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11744 try:
745 input_api.subprocess.check_output(args)
746 return []
747 except input_api.subprocess.CalledProcessError as error:
748 return [output_api.PresubmitError(
749 'checkperms.py failed:',
750 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22751
752
robertocn832f5992017-01-04 19:01:30753def _CheckTeamTags(input_api, output_api):
754 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
755 checkteamtags_tool = input_api.os_path.join(
756 input_api.PresubmitLocalPath(),
757 'tools', 'checkteamtags', 'checkteamtags.py')
758 args = [input_api.python_executable, checkteamtags_tool,
759 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22760 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30761 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
762 'OWNERS']
763 try:
764 if files:
765 input_api.subprocess.check_output(args + files)
766 return []
767 except input_api.subprocess.CalledProcessError as error:
768 return [output_api.PresubmitError(
769 'checkteamtags.py failed:',
770 long_text=error.output)]
771
772
[email protected]c8278b32012-10-30 20:35:49773def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
774 """Makes sure we don't include ui/aura/window_property.h
775 in header files.
776 """
777 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
778 errors = []
779 for f in input_api.AffectedFiles():
780 if not f.LocalPath().endswith('.h'):
781 continue
782 for line_num, line in f.ChangedContents():
783 if pattern.match(line):
784 errors.append(' %s:%d' % (f.LocalPath(), line_num))
785
786 results = []
787 if errors:
788 results.append(output_api.PresubmitError(
789 'Header files should not include ui/aura/window_property.h', errors))
790 return results
791
792
[email protected]cf9b78f2012-11-14 11:40:28793def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
794 """Checks that the lines in scope occur in the right order.
795
796 1. C system files in alphabetical order
797 2. C++ system files in alphabetical order
798 3. Project's .h files
799 """
800
801 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
802 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
803 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
804
805 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
806
807 state = C_SYSTEM_INCLUDES
808
809 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57810 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28811 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55812 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28813 for line_num, line in scope:
814 if c_system_include_pattern.match(line):
815 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55816 problem_linenums.append((line_num, previous_line_num,
817 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28818 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55819 problem_linenums.append((line_num, previous_line_num,
820 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28821 elif cpp_system_include_pattern.match(line):
822 if state == C_SYSTEM_INCLUDES:
823 state = CPP_SYSTEM_INCLUDES
824 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55825 problem_linenums.append((line_num, previous_line_num,
826 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28827 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55828 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28829 elif custom_include_pattern.match(line):
830 if state != CUSTOM_INCLUDES:
831 state = CUSTOM_INCLUDES
832 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55833 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28834 else:
brucedawson70fadb02015-06-30 17:47:55835 problem_linenums.append((line_num, previous_line_num,
836 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28837 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57838 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28839
840 warnings = []
brucedawson70fadb02015-06-30 17:47:55841 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57842 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55843 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28844 return warnings
845
846
[email protected]ac294a12012-12-06 16:38:43847def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28848 """Checks the #include order for the given file f."""
849
[email protected]2299dcf2012-11-15 19:56:24850 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30851 # Exclude the following includes from the check:
852 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
853 # specific order.
854 # 2) <atlbase.h>, "build/build_config.h"
855 excluded_include_pattern = input_api.re.compile(
856 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24857 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33858 # Match the final or penultimate token if it is xxxtest so we can ignore it
859 # when considering the special first include.
860 test_file_tag_pattern = input_api.re.compile(
861 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11862 if_pattern = input_api.re.compile(
863 r'\s*#\s*(if|elif|else|endif|define|undef).*')
864 # Some files need specialized order of includes; exclude such files from this
865 # check.
866 uncheckable_includes_pattern = input_api.re.compile(
867 r'\s*#include '
868 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28869
870 contents = f.NewContents()
871 warnings = []
872 line_num = 0
873
[email protected]ac294a12012-12-06 16:38:43874 # Handle the special first include. If the first include file is
875 # some/path/file.h, the corresponding including file can be some/path/file.cc,
876 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
877 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33878 # If the included file is some/path/file_platform.h the including file could
879 # also be some/path/file_xxxtest_platform.h.
880 including_file_base_name = test_file_tag_pattern.sub(
881 '', input_api.os_path.basename(f.LocalPath()))
882
[email protected]ac294a12012-12-06 16:38:43883 for line in contents:
884 line_num += 1
885 if system_include_pattern.match(line):
886 # No special first include -> process the line again along with normal
887 # includes.
888 line_num -= 1
889 break
890 match = custom_include_pattern.match(line)
891 if match:
892 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33893 header_basename = test_file_tag_pattern.sub(
894 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
895
896 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24897 # No special first include -> process the line again along with normal
898 # includes.
899 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43900 break
[email protected]cf9b78f2012-11-14 11:40:28901
902 # Split into scopes: Each region between #if and #endif is its own scope.
903 scopes = []
904 current_scope = []
905 for line in contents[line_num:]:
906 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11907 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54908 continue
[email protected]2309b0fa02012-11-16 12:18:27909 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28910 scopes.append(current_scope)
911 current_scope = []
[email protected]962f117e2012-11-22 18:11:56912 elif ((system_include_pattern.match(line) or
913 custom_include_pattern.match(line)) and
914 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28915 current_scope.append((line_num, line))
916 scopes.append(current_scope)
917
918 for scope in scopes:
919 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
920 changed_linenums))
921 return warnings
922
923
924def _CheckIncludeOrder(input_api, output_api):
925 """Checks that the #include order is correct.
926
927 1. The corresponding header for source files.
928 2. C system files in alphabetical order
929 3. C++ system files in alphabetical order
930 4. Project's .h files in alphabetical order
931
[email protected]ac294a12012-12-06 16:38:43932 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
933 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28934 """
[email protected]e120b012014-08-15 19:08:35935 def FileFilterIncludeOrder(affected_file):
936 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
937 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28938
939 warnings = []
[email protected]e120b012014-08-15 19:08:35940 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08941 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43942 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
943 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28944
945 results = []
946 if warnings:
[email protected]f7051d52013-04-02 18:31:42947 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53948 warnings))
[email protected]cf9b78f2012-11-14 11:40:28949 return results
950
951
[email protected]70ca77752012-11-20 03:45:03952def _CheckForVersionControlConflictsInFile(input_api, f):
953 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
954 errors = []
955 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23956 if f.LocalPath().endswith('.md'):
957 # First-level headers in markdown look a lot like version control
958 # conflict markers. http://daringfireball.net/projects/markdown/basics
959 continue
[email protected]70ca77752012-11-20 03:45:03960 if pattern.match(line):
961 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
962 return errors
963
964
965def _CheckForVersionControlConflicts(input_api, output_api):
966 """Usually this is not intentional and will cause a compile failure."""
967 errors = []
968 for f in input_api.AffectedFiles():
969 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
970
971 results = []
972 if errors:
973 results.append(output_api.PresubmitError(
974 'Version control conflict markers found, please resolve.', errors))
975 return results
976
estadee17314a02017-01-12 16:22:16977def _CheckGoogleSupportAnswerUrl(input_api, output_api):
978 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
979 errors = []
980 for f in input_api.AffectedFiles():
981 for line_num, line in f.ChangedContents():
982 if pattern.search(line):
983 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
984
985 results = []
986 if errors:
987 results.append(output_api.PresubmitPromptWarning(
988 'Found Google support URL addressed by answer number. Please replace with '
989 'a p= identifier instead. See crbug.com/679462\n', errors))
990 return results
991
[email protected]70ca77752012-11-20 03:45:03992
[email protected]06e6d0ff2012-12-11 01:36:44993def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
994 def FilterFile(affected_file):
995 """Filter function for use with input_api.AffectedSourceFiles,
996 below. This filters out everything except non-test files from
997 top-level directories that generally speaking should not hard-code
998 service URLs (e.g. src/android_webview/, src/content/ and others).
999 """
1000 return input_api.FilterSourceFile(
1001 affected_file,
[email protected]78bb39d62012-12-11 15:11:561002 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441003 black_list=(_EXCLUDED_PATHS +
1004 _TEST_CODE_EXCLUDED_PATHS +
1005 input_api.DEFAULT_BLACK_LIST))
1006
reillyi38965732015-11-16 18:27:331007 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1008 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461009 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1010 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441011 problems = [] # items are (filename, line_number, line)
1012 for f in input_api.AffectedSourceFiles(FilterFile):
1013 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461014 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441015 problems.append((f.LocalPath(), line_num, line))
1016
1017 if problems:
[email protected]f7051d52013-04-02 18:31:421018 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441019 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581020 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441021 [' %s:%d: %s' % (
1022 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031023 else:
1024 return []
[email protected]06e6d0ff2012-12-11 01:36:441025
1026
[email protected]d2530012013-01-25 16:39:271027def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1028 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311029 The native_client_sdk directory is excluded because it has auto-generated PNG
1030 files for documentation.
[email protected]d2530012013-01-25 16:39:271031 """
[email protected]d2530012013-01-25 16:39:271032 errors = []
binji0dcdf342014-12-12 18:32:311033 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1034 black_list = (r'^native_client_sdk[\\\/]',)
1035 file_filter = lambda f: input_api.FilterSourceFile(
1036 f, white_list=white_list, black_list=black_list)
1037 for f in input_api.AffectedFiles(include_deletes=False,
1038 file_filter=file_filter):
1039 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271040
1041 results = []
1042 if errors:
1043 results.append(output_api.PresubmitError(
1044 'The name of PNG files should not have abbreviations. \n'
1045 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1046 'Contact [email protected] if you have questions.', errors))
1047 return results
1048
1049
[email protected]14a6131c2014-01-08 01:15:411050def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:081051 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411052 a set of DEPS entries that we should look up.
1053
1054 For a directory (rather than a specific filename) we fake a path to
1055 a specific filename by adding /DEPS. This is chosen as a file that
1056 will seldom or never be subject to per-file include_rules.
1057 """
[email protected]2b438d62013-11-14 17:54:141058 # We ignore deps entries on auto-generated directories.
1059 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081060
1061 # This pattern grabs the path without basename in the first
1062 # parentheses, and the basename (if present) in the second. It
1063 # relies on the simple heuristic that if there is a basename it will
1064 # be a header file ending in ".h".
1065 pattern = re.compile(
1066 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141067 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081068 for changed_line in changed_lines:
1069 m = pattern.match(changed_line)
1070 if m:
1071 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141072 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411073 if m.group(2):
1074 results.add('%s%s' % (path, m.group(2)))
1075 else:
1076 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081077 return results
1078
1079
[email protected]e871964c2013-05-13 14:14:551080def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1081 """When a dependency prefixed with + is added to a DEPS file, we
1082 want to make sure that the change is reviewed by an OWNER of the
1083 target file or directory, to avoid layering violations from being
1084 introduced. This check verifies that this happens.
1085 """
1086 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241087
1088 file_filter = lambda f: not input_api.re.match(
1089 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1090 for f in input_api.AffectedFiles(include_deletes=False,
1091 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551092 filename = input_api.os_path.basename(f.LocalPath())
1093 if filename == 'DEPS':
1094 changed_lines |= set(line.strip()
1095 for line_num, line
1096 in f.ChangedContents())
1097 if not changed_lines:
1098 return []
1099
[email protected]14a6131c2014-01-08 01:15:411100 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1101 changed_lines)
[email protected]e871964c2013-05-13 14:14:551102 if not virtual_depended_on_files:
1103 return []
1104
1105 if input_api.is_committing:
1106 if input_api.tbr:
1107 return [output_api.PresubmitNotifyResult(
1108 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271109 if input_api.dry_run:
1110 return [output_api.PresubmitNotifyResult(
1111 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551112 if not input_api.change.issue:
1113 return [output_api.PresubmitError(
1114 "DEPS approval by OWNERS check failed: this change has "
1115 "no Rietveld issue number, so we can't check it for approvals.")]
1116 output = output_api.PresubmitError
1117 else:
1118 output = output_api.PresubmitNotifyResult
1119
1120 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501121 owner_email, reviewers = (
1122 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1123 input_api,
1124 owners_db.email_regexp,
1125 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551126
1127 owner_email = owner_email or input_api.change.author_email
1128
[email protected]de4f7d22013-05-23 14:27:461129 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511130 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461131 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551132 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1133 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411134
1135 # We strip the /DEPS part that was added by
1136 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1137 # directory.
1138 def StripDeps(path):
1139 start_deps = path.rfind('/DEPS')
1140 if start_deps != -1:
1141 return path[:start_deps]
1142 else:
1143 return path
1144 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551145 for path in missing_files]
1146
1147 if unapproved_dependencies:
1148 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151149 output('You need LGTM from owners of depends-on paths in DEPS that were '
1150 'modified in this CL:\n %s' %
1151 '\n '.join(sorted(unapproved_dependencies)))]
1152 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1153 output_list.append(output(
1154 'Suggested missing target path OWNERS:\n %s' %
1155 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551156 return output_list
1157
1158 return []
1159
1160
[email protected]85218562013-11-22 07:41:401161def _CheckSpamLogging(input_api, output_api):
1162 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1163 black_list = (_EXCLUDED_PATHS +
1164 _TEST_CODE_EXCLUDED_PATHS +
1165 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501166 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191167 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481168 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461169 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121170 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1171 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581172 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161173 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031174 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151175 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1176 r"^chromecast[\\\/]",
1177 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311178 r"^components[\\\/]html_viewer[\\\/]"
1179 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461180 # TODO(peter): Remove this exception. https://crbug.com/534537
1181 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1182 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251183 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1184 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241185 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111186 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151187 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111188 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521189 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501190 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361191 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311192 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131193 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441194 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451195 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021196 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351197 r"dump_file_system.cc$",
1198 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401199 source_file_filter = lambda x: input_api.FilterSourceFile(
1200 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1201
1202 log_info = []
1203 printf = []
1204
1205 for f in input_api.AffectedSourceFiles(source_file_filter):
1206 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471207 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401208 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471209 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131210 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371211
mohan.reddyf21db962014-10-16 12:26:471212 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371213 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471214 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401215 printf.append(f.LocalPath())
1216
1217 if log_info:
1218 return [output_api.PresubmitError(
1219 'These files spam the console log with LOG(INFO):',
1220 items=log_info)]
1221 if printf:
1222 return [output_api.PresubmitError(
1223 'These files spam the console log with printf/fprintf:',
1224 items=printf)]
1225 return []
1226
1227
[email protected]49aa76a2013-12-04 06:59:161228def _CheckForAnonymousVariables(input_api, output_api):
1229 """These types are all expected to hold locks while in scope and
1230 so should never be anonymous (which causes them to be immediately
1231 destroyed)."""
1232 they_who_must_be_named = [
1233 'base::AutoLock',
1234 'base::AutoReset',
1235 'base::AutoUnlock',
1236 'SkAutoAlphaRestore',
1237 'SkAutoBitmapShaderInstall',
1238 'SkAutoBlitterChoose',
1239 'SkAutoBounderCommit',
1240 'SkAutoCallProc',
1241 'SkAutoCanvasRestore',
1242 'SkAutoCommentBlock',
1243 'SkAutoDescriptor',
1244 'SkAutoDisableDirectionCheck',
1245 'SkAutoDisableOvalCheck',
1246 'SkAutoFree',
1247 'SkAutoGlyphCache',
1248 'SkAutoHDC',
1249 'SkAutoLockColors',
1250 'SkAutoLockPixels',
1251 'SkAutoMalloc',
1252 'SkAutoMaskFreeImage',
1253 'SkAutoMutexAcquire',
1254 'SkAutoPathBoundsUpdate',
1255 'SkAutoPDFRelease',
1256 'SkAutoRasterClipValidate',
1257 'SkAutoRef',
1258 'SkAutoTime',
1259 'SkAutoTrace',
1260 'SkAutoUnref',
1261 ]
1262 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1263 # bad: base::AutoLock(lock.get());
1264 # not bad: base::AutoLock lock(lock.get());
1265 bad_pattern = input_api.re.compile(anonymous)
1266 # good: new base::AutoLock(lock.get())
1267 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1268 errors = []
1269
1270 for f in input_api.AffectedFiles():
1271 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1272 continue
1273 for linenum, line in f.ChangedContents():
1274 if bad_pattern.search(line) and not good_pattern.search(line):
1275 errors.append('%s:%d' % (f.LocalPath(), linenum))
1276
1277 if errors:
1278 return [output_api.PresubmitError(
1279 'These lines create anonymous variables that need to be named:',
1280 items=errors)]
1281 return []
1282
1283
[email protected]5fe0f8742013-11-29 01:04:591284def _CheckCygwinShell(input_api, output_api):
1285 source_file_filter = lambda x: input_api.FilterSourceFile(
1286 x, white_list=(r'.+\.(gyp|gypi)$',))
1287 cygwin_shell = []
1288
1289 for f in input_api.AffectedSourceFiles(source_file_filter):
1290 for linenum, line in f.ChangedContents():
1291 if 'msvs_cygwin_shell' in line:
1292 cygwin_shell.append(f.LocalPath())
1293 break
1294
1295 if cygwin_shell:
1296 return [output_api.PresubmitError(
1297 'These files should not use msvs_cygwin_shell (the default is 0):',
1298 items=cygwin_shell)]
1299 return []
1300
[email protected]85218562013-11-22 07:41:401301
[email protected]999261d2014-03-03 20:08:081302def _CheckUserActionUpdate(input_api, output_api):
1303 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521304 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081305 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521306 # If actions.xml is already included in the changelist, the PRESUBMIT
1307 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081308 return []
1309
[email protected]999261d2014-03-03 20:08:081310 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1311 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521312 current_actions = None
[email protected]999261d2014-03-03 20:08:081313 for f in input_api.AffectedFiles(file_filter=file_filter):
1314 for line_num, line in f.ChangedContents():
1315 match = input_api.re.search(action_re, line)
1316 if match:
[email protected]2f92dec2014-03-07 19:21:521317 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1318 # loaded only once.
1319 if not current_actions:
1320 with open('tools/metrics/actions/actions.xml') as actions_f:
1321 current_actions = actions_f.read()
1322 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081323 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521324 action = 'name="{0}"'.format(action_name)
1325 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081326 return [output_api.PresubmitPromptWarning(
1327 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521328 'tools/metrics/actions/actions.xml. Please run '
1329 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081330 % (f.LocalPath(), line_num, action_name))]
1331 return []
1332
1333
[email protected]99171a92014-06-03 08:44:471334def _GetJSONParseError(input_api, filename, eat_comments=True):
1335 try:
1336 contents = input_api.ReadFile(filename)
1337 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131338 import sys
1339 original_sys_path = sys.path
1340 try:
1341 sys.path = sys.path + [input_api.os_path.join(
1342 input_api.PresubmitLocalPath(),
1343 'tools', 'json_comment_eater')]
1344 import json_comment_eater
1345 finally:
1346 sys.path = original_sys_path
1347 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471348
1349 input_api.json.loads(contents)
1350 except ValueError as e:
1351 return e
1352 return None
1353
1354
1355def _GetIDLParseError(input_api, filename):
1356 try:
1357 contents = input_api.ReadFile(filename)
1358 idl_schema = input_api.os_path.join(
1359 input_api.PresubmitLocalPath(),
1360 'tools', 'json_schema_compiler', 'idl_schema.py')
1361 process = input_api.subprocess.Popen(
1362 [input_api.python_executable, idl_schema],
1363 stdin=input_api.subprocess.PIPE,
1364 stdout=input_api.subprocess.PIPE,
1365 stderr=input_api.subprocess.PIPE,
1366 universal_newlines=True)
1367 (_, error) = process.communicate(input=contents)
1368 return error or None
1369 except ValueError as e:
1370 return e
1371
1372
1373def _CheckParseErrors(input_api, output_api):
1374 """Check that IDL and JSON files do not contain syntax errors."""
1375 actions = {
1376 '.idl': _GetIDLParseError,
1377 '.json': _GetJSONParseError,
1378 }
1379 # These paths contain test data and other known invalid JSON files.
1380 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491381 r'test[\\\/]data[\\\/]',
1382 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471383 ]
1384 # Most JSON files are preprocessed and support comments, but these do not.
1385 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491386 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471387 ]
1388 # Only run IDL checker on files in these directories.
1389 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491390 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1391 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471392 ]
1393
1394 def get_action(affected_file):
1395 filename = affected_file.LocalPath()
1396 return actions.get(input_api.os_path.splitext(filename)[1])
1397
1398 def MatchesFile(patterns, path):
1399 for pattern in patterns:
1400 if input_api.re.search(pattern, path):
1401 return True
1402 return False
1403
1404 def FilterFile(affected_file):
1405 action = get_action(affected_file)
1406 if not action:
1407 return False
1408 path = affected_file.LocalPath()
1409
1410 if MatchesFile(excluded_patterns, path):
1411 return False
1412
1413 if (action == _GetIDLParseError and
1414 not MatchesFile(idl_included_patterns, path)):
1415 return False
1416 return True
1417
1418 results = []
1419 for affected_file in input_api.AffectedFiles(
1420 file_filter=FilterFile, include_deletes=False):
1421 action = get_action(affected_file)
1422 kwargs = {}
1423 if (action == _GetJSONParseError and
1424 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1425 kwargs['eat_comments'] = False
1426 parse_error = action(input_api,
1427 affected_file.AbsoluteLocalPath(),
1428 **kwargs)
1429 if parse_error:
1430 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1431 (affected_file.LocalPath(), parse_error)))
1432 return results
1433
1434
[email protected]760deea2013-12-10 19:33:491435def _CheckJavaStyle(input_api, output_api):
1436 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471437 import sys
[email protected]760deea2013-12-10 19:33:491438 original_sys_path = sys.path
1439 try:
1440 sys.path = sys.path + [input_api.os_path.join(
1441 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1442 import checkstyle
1443 finally:
1444 # Restore sys.path to what it was before.
1445 sys.path = original_sys_path
1446
1447 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091448 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511449 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491450
1451
dchenge07de812016-06-20 19:27:171452def _CheckIpcOwners(input_api, output_api):
1453 """Checks that affected files involving IPC have an IPC OWNERS rule.
1454
1455 Whether or not a file affects IPC is determined by a simple whitelist of
1456 filename patterns."""
1457 file_patterns = [
palmerb19a0932017-01-24 04:00:311458 # Legacy IPC:
dchenge07de812016-06-20 19:27:171459 '*_messages.cc',
1460 '*_messages*.h',
1461 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311462 # Mojo IPC:
dchenge07de812016-06-20 19:27:171463 '*.mojom',
1464 '*_struct_traits*.*',
1465 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311466 '*.typemap',
1467 # Android native IPC:
1468 '*.aidl',
1469 # Blink uses a different file naming convention:
1470 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171471 '*StructTraits*.*',
1472 '*TypeConverter*.*',
1473 ]
1474
scottmg7a6ed5ba2016-11-04 18:22:041475 # These third_party directories do not contain IPCs, but contain files
1476 # matching the above patterns, which trigger false positives.
1477 exclude_paths = [
1478 'third_party/crashpad/*',
1479 ]
1480
dchenge07de812016-06-20 19:27:171481 # Dictionary mapping an OWNERS file path to Patterns.
1482 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1483 # rules ) to a PatternEntry.
1484 # PatternEntry is a dictionary with two keys:
1485 # - 'files': the files that are matched by this pattern
1486 # - 'rules': the per-file rules needed for this pattern
1487 # For example, if we expect OWNERS file to contain rules for *.mojom and
1488 # *_struct_traits*.*, Patterns might look like this:
1489 # {
1490 # '*.mojom': {
1491 # 'files': ...,
1492 # 'rules': [
1493 # 'per-file *.mojom=set noparent',
1494 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1495 # ],
1496 # },
1497 # '*_struct_traits*.*': {
1498 # 'files': ...,
1499 # 'rules': [
1500 # 'per-file *_struct_traits*.*=set noparent',
1501 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1502 # ],
1503 # },
1504 # }
1505 to_check = {}
1506
1507 # Iterate through the affected files to see what we actually need to check
1508 # for. We should only nag patch authors about per-file rules if a file in that
1509 # directory would match that pattern. If a directory only contains *.mojom
1510 # files and no *_messages*.h files, we should only nag about rules for
1511 # *.mojom files.
rockot51249332016-06-23 16:32:251512 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171513 for pattern in file_patterns:
1514 if input_api.fnmatch.fnmatch(
1515 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041516 skip = False
1517 for exclude in exclude_paths:
1518 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1519 skip = True
1520 break
1521 if skip:
1522 continue
dchenge07de812016-06-20 19:27:171523 owners_file = input_api.os_path.join(
1524 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1525 if owners_file not in to_check:
1526 to_check[owners_file] = {}
1527 if pattern not in to_check[owners_file]:
1528 to_check[owners_file][pattern] = {
1529 'files': [],
1530 'rules': [
1531 'per-file %s=set noparent' % pattern,
1532 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1533 ]
1534 }
1535 to_check[owners_file][pattern]['files'].append(f)
1536 break
1537
1538 # Now go through the OWNERS files we collected, filtering out rules that are
1539 # already present in that OWNERS file.
1540 for owners_file, patterns in to_check.iteritems():
1541 try:
1542 with file(owners_file) as f:
1543 lines = set(f.read().splitlines())
1544 for entry in patterns.itervalues():
1545 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1546 ]
1547 except IOError:
1548 # No OWNERS file, so all the rules are definitely missing.
1549 continue
1550
1551 # All the remaining lines weren't found in OWNERS files, so emit an error.
1552 errors = []
1553 for owners_file, patterns in to_check.iteritems():
1554 missing_lines = []
1555 files = []
1556 for pattern, entry in patterns.iteritems():
1557 missing_lines.extend(entry['rules'])
1558 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1559 if missing_lines:
1560 errors.append(
1561 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1562 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1563
1564 results = []
1565 if errors:
vabrf5ce3bf92016-07-11 14:52:411566 if input_api.is_committing:
1567 output = output_api.PresubmitError
1568 else:
1569 output = output_api.PresubmitPromptWarning
1570 results.append(output(
dchenge07de812016-06-20 19:27:171571 'Found changes to IPC files without a security OWNER!',
1572 long_text='\n\n'.join(errors)))
1573
1574 return results
1575
1576
jbriance9e12f162016-11-25 07:57:501577def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311578 """Checks that added or removed lines in non third party affected
1579 header files do not lead to new useless class or struct forward
1580 declaration.
jbriance9e12f162016-11-25 07:57:501581 """
1582 results = []
1583 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1584 input_api.re.MULTILINE)
1585 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1586 input_api.re.MULTILINE)
1587 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311588 if (f.LocalPath().startswith('third_party') and
1589 not f.LocalPath().startswith('third_party/WebKit') and
1590 not f.LocalPath().startswith('third_party\\WebKit')):
1591 continue
1592
jbriance9e12f162016-11-25 07:57:501593 if not f.LocalPath().endswith('.h'):
1594 continue
1595
1596 contents = input_api.ReadFile(f)
1597 fwd_decls = input_api.re.findall(class_pattern, contents)
1598 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1599
1600 useless_fwd_decls = []
1601 for decl in fwd_decls:
1602 count = sum(1 for _ in input_api.re.finditer(
1603 r'\b%s\b' % input_api.re.escape(decl), contents))
1604 if count == 1:
1605 useless_fwd_decls.append(decl)
1606
1607 if not useless_fwd_decls:
1608 continue
1609
1610 for line in f.GenerateScmDiff().splitlines():
1611 if (line.startswith('-') and not line.startswith('--') or
1612 line.startswith('+') and not line.startswith('++')):
1613 for decl in useless_fwd_decls:
1614 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1615 results.append(output_api.PresubmitPromptWarning(
1616 '%s: %s forward declaration is becoming useless' %
1617 (f.LocalPath(), decl)))
1618 useless_fwd_decls.remove(decl)
1619
1620 return results
1621
1622
dskiba88634f4e2015-08-14 23:03:291623def _CheckAndroidToastUsage(input_api, output_api):
1624 """Checks that code uses org.chromium.ui.widget.Toast instead of
1625 android.widget.Toast (Chromium Toast doesn't force hardware
1626 acceleration on low-end devices, saving memory).
1627 """
1628 toast_import_pattern = input_api.re.compile(
1629 r'^import android\.widget\.Toast;$')
1630
1631 errors = []
1632
1633 sources = lambda affected_file: input_api.FilterSourceFile(
1634 affected_file,
1635 black_list=(_EXCLUDED_PATHS +
1636 _TEST_CODE_EXCLUDED_PATHS +
1637 input_api.DEFAULT_BLACK_LIST +
1638 (r'^chromecast[\\\/].*',
1639 r'^remoting[\\\/].*')),
1640 white_list=(r'.*\.java$',))
1641
1642 for f in input_api.AffectedSourceFiles(sources):
1643 for line_num, line in f.ChangedContents():
1644 if toast_import_pattern.search(line):
1645 errors.append("%s:%d" % (f.LocalPath(), line_num))
1646
1647 results = []
1648
1649 if errors:
1650 results.append(output_api.PresubmitError(
1651 'android.widget.Toast usage is detected. Android toasts use hardware'
1652 ' acceleration, and can be\ncostly on low-end devices. Please use'
1653 ' org.chromium.ui.widget.Toast instead.\n'
1654 'Contact [email protected] if you have any questions.',
1655 errors))
1656
1657 return results
1658
1659
dgnaa68d5e2015-06-10 10:08:221660def _CheckAndroidCrLogUsage(input_api, output_api):
1661 """Checks that new logs using org.chromium.base.Log:
1662 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511663 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221664 """
pkotwicza1dd0b002016-05-16 14:41:041665
1666 # Do not check format of logs in //chrome/android/webapk because
1667 # //chrome/android/webapk cannot depend on //base
1668 cr_log_check_excluded_paths = [
1669 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1670 ]
1671
dgnaa68d5e2015-06-10 10:08:221672 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121673 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1674 class_in_base_pattern = input_api.re.compile(
1675 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1676 has_some_log_import_pattern = input_api.re.compile(
1677 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221678 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121679 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221680 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511681 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221682 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221683
Vincent Scheib16d7b272015-09-15 18:09:071684 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221685 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041686 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1687 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121688
dgnaa68d5e2015-06-10 10:08:221689 tag_decl_errors = []
1690 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121691 tag_errors = []
dgn38736db2015-09-18 19:20:511692 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121693 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221694
1695 for f in input_api.AffectedSourceFiles(sources):
1696 file_content = input_api.ReadFile(f)
1697 has_modified_logs = False
1698
1699 # Per line checks
dgn87d9fb62015-06-12 09:15:121700 if (cr_log_import_pattern.search(file_content) or
1701 (class_in_base_pattern.search(file_content) and
1702 not has_some_log_import_pattern.search(file_content))):
1703 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221704 for line_num, line in f.ChangedContents():
1705
1706 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121707 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221708 if match:
1709 has_modified_logs = True
1710
1711 # Make sure it uses "TAG"
1712 if not match.group('tag') == 'TAG':
1713 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121714 else:
1715 # Report non cr Log function calls in changed lines
1716 for line_num, line in f.ChangedContents():
1717 if log_call_pattern.search(line):
1718 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221719
1720 # Per file checks
1721 if has_modified_logs:
1722 # Make sure the tag is using the "cr" prefix and is not too long
1723 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511724 tag_name = match.group('name') if match else None
1725 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221726 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511727 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221728 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511729 elif '.' in tag_name:
1730 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221731
1732 results = []
1733 if tag_decl_errors:
1734 results.append(output_api.PresubmitPromptWarning(
1735 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511736 '"private static final String TAG = "<package tag>".\n'
1737 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221738 tag_decl_errors))
1739
1740 if tag_length_errors:
1741 results.append(output_api.PresubmitError(
1742 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511743 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221744 tag_length_errors))
1745
1746 if tag_errors:
1747 results.append(output_api.PresubmitPromptWarning(
1748 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1749 tag_errors))
1750
dgn87d9fb62015-06-12 09:15:121751 if util_log_errors:
dgn4401aa52015-04-29 16:26:171752 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121753 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1754 util_log_errors))
1755
dgn38736db2015-09-18 19:20:511756 if tag_with_dot_errors:
1757 results.append(output_api.PresubmitPromptWarning(
1758 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1759 tag_with_dot_errors))
1760
dgn4401aa52015-04-29 16:26:171761 return results
1762
1763
yolandyan45001472016-12-21 21:12:421764def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1765 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1766 deprecated_annotation_import_pattern = input_api.re.compile(
1767 r'^import android\.test\.suitebuilder\.annotation\..*;',
1768 input_api.re.MULTILINE)
1769 sources = lambda x: input_api.FilterSourceFile(
1770 x, white_list=(r'.*\.java$',), black_list=None)
1771 errors = []
1772 for f in input_api.AffectedFiles(sources):
1773 for line_num, line in f.ChangedContents():
1774 if deprecated_annotation_import_pattern.search(line):
1775 errors.append("%s:%d" % (f.LocalPath(), line_num))
1776
1777 results = []
1778 if errors:
1779 results.append(output_api.PresubmitError(
1780 'Annotations in android.test.suitebuilder.annotation have been'
1781 ' deprecated since API level 24. Please use android.support.test.filters'
1782 ' from //third_party/android_support_test_runner:runner_java instead.'
1783 ' Contact [email protected] if you have any questions.', errors))
1784 return results
1785
1786
agrieve7b6479d82015-10-07 14:24:221787def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1788 """Checks if MDPI assets are placed in a correct directory."""
1789 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1790 ('/res/drawable/' in f.LocalPath() or
1791 '/res/drawable-ldrtl/' in f.LocalPath()))
1792 errors = []
1793 for f in input_api.AffectedFiles(include_deletes=False,
1794 file_filter=file_filter):
1795 errors.append(' %s' % f.LocalPath())
1796
1797 results = []
1798 if errors:
1799 results.append(output_api.PresubmitError(
1800 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1801 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1802 '/res/drawable-ldrtl/.\n'
1803 'Contact [email protected] if you have questions.', errors))
1804 return results
1805
1806
agrievef32bcc72016-04-04 14:57:401807class PydepsChecker(object):
1808 def __init__(self, input_api, pydeps_files):
1809 self._file_cache = {}
1810 self._input_api = input_api
1811 self._pydeps_files = pydeps_files
1812
1813 def _LoadFile(self, path):
1814 """Returns the list of paths within a .pydeps file relative to //."""
1815 if path not in self._file_cache:
1816 with open(path) as f:
1817 self._file_cache[path] = f.read()
1818 return self._file_cache[path]
1819
1820 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1821 """Returns an interable of paths within the .pydep, relativized to //."""
1822 os_path = self._input_api.os_path
1823 pydeps_dir = os_path.dirname(pydeps_path)
1824 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1825 if not l.startswith('*'))
1826 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1827
1828 def _CreateFilesToPydepsMap(self):
1829 """Returns a map of local_path -> list_of_pydeps."""
1830 ret = {}
1831 for pydep_local_path in self._pydeps_files:
1832 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1833 ret.setdefault(path, []).append(pydep_local_path)
1834 return ret
1835
1836 def ComputeAffectedPydeps(self):
1837 """Returns an iterable of .pydeps files that might need regenerating."""
1838 affected_pydeps = set()
1839 file_to_pydeps_map = None
1840 for f in self._input_api.AffectedFiles(include_deletes=True):
1841 local_path = f.LocalPath()
1842 if local_path == 'DEPS':
1843 return self._pydeps_files
1844 elif local_path.endswith('.pydeps'):
1845 if local_path in self._pydeps_files:
1846 affected_pydeps.add(local_path)
1847 elif local_path.endswith('.py'):
1848 if file_to_pydeps_map is None:
1849 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1850 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1851 return affected_pydeps
1852
1853 def DetermineIfStale(self, pydeps_path):
1854 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411855 import difflib
agrievef32bcc72016-04-04 14:57:401856 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1857 cmd = old_pydeps_data[1][1:].strip()
1858 new_pydeps_data = self._input_api.subprocess.check_output(
1859 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411860 old_contents = old_pydeps_data[2:]
1861 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401862 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411863 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401864
1865
1866def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1867 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001868 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281869 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1870 # Mac, so skip it on other platforms.
1871 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001872 return []
agrievef32bcc72016-04-04 14:57:401873 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1874 is_android = input_api.os_path.exists('third_party/android_tools')
1875 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1876 results = []
1877 # First, check for new / deleted .pydeps.
1878 for f in input_api.AffectedFiles(include_deletes=True):
1879 if f.LocalPath().endswith('.pydeps'):
1880 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1881 results.append(output_api.PresubmitError(
1882 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1883 'remove %s' % f.LocalPath()))
1884 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1885 results.append(output_api.PresubmitError(
1886 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1887 'include %s' % f.LocalPath()))
1888
1889 if results:
1890 return results
1891
1892 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1893
1894 for pydep_path in checker.ComputeAffectedPydeps():
1895 try:
phajdan.jr0d9878552016-11-04 10:49:411896 result = checker.DetermineIfStale(pydep_path)
1897 if result:
1898 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401899 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411900 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1901 'To regenerate, run:\n\n %s' %
1902 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401903 except input_api.subprocess.CalledProcessError as error:
1904 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1905 long_text=error.output)]
1906
1907 return results
1908
1909
glidere61efad2015-02-18 17:39:431910def _CheckSingletonInHeaders(input_api, output_api):
1911 """Checks to make sure no header files have |Singleton<|."""
1912 def FileFilter(affected_file):
1913 # It's ok for base/memory/singleton.h to have |Singleton<|.
1914 black_list = (_EXCLUDED_PATHS +
1915 input_api.DEFAULT_BLACK_LIST +
1916 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1917 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1918
sergeyu34d21222015-09-16 00:11:441919 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431920 files = []
1921 for f in input_api.AffectedSourceFiles(FileFilter):
1922 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1923 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1924 contents = input_api.ReadFile(f)
1925 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241926 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431927 pattern.search(line)):
1928 files.append(f)
1929 break
1930
1931 if files:
yolandyandaabc6d2016-04-18 18:29:391932 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441933 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431934 'Please move them to an appropriate source file so that the ' +
1935 'template gets instantiated in a single compilation unit.',
1936 files) ]
1937 return []
1938
1939
dbeam1ec68ac2016-12-15 05:22:241940def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:201941 """Checks for old style compiled_resources.gyp files."""
1942 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1943
1944 added_compiled_resources = filter(is_compiled_resource, [
1945 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1946 ])
1947
1948 if not added_compiled_resources:
1949 return []
1950
1951 return [output_api.PresubmitError(
1952 "Found new compiled_resources.gyp files:\n%s\n\n"
1953 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551954 "please use compiled_resources2.gyp instead:\n"
1955 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1956 %
dbeam37e8e7402016-02-10 22:58:201957 "\n".join(added_compiled_resources))]
1958
1959
[email protected]fd20b902014-05-09 02:14:531960_DEPRECATED_CSS = [
1961 # Values
1962 ( "-webkit-box", "flex" ),
1963 ( "-webkit-inline-box", "inline-flex" ),
1964 ( "-webkit-flex", "flex" ),
1965 ( "-webkit-inline-flex", "inline-flex" ),
1966 ( "-webkit-min-content", "min-content" ),
1967 ( "-webkit-max-content", "max-content" ),
1968
1969 # Properties
1970 ( "-webkit-background-clip", "background-clip" ),
1971 ( "-webkit-background-origin", "background-origin" ),
1972 ( "-webkit-background-size", "background-size" ),
1973 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441974 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531975
1976 # Functions
1977 ( "-webkit-gradient", "gradient" ),
1978 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1979 ( "-webkit-linear-gradient", "linear-gradient" ),
1980 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1981 ( "-webkit-radial-gradient", "radial-gradient" ),
1982 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1983]
1984
dbeam1ec68ac2016-12-15 05:22:241985def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531986 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251987 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341988 documentation and iOS CSS for dom distiller
1989 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251990 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531991 results = []
dbeam070cfe62014-10-22 06:44:021992 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251993 black_list = (_EXCLUDED_PATHS +
1994 _TEST_CODE_EXCLUDED_PATHS +
1995 input_api.DEFAULT_BLACK_LIST +
1996 (r"^chrome/common/extensions/docs",
1997 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341998 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051999 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442000 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252001 r"^native_client_sdk"))
2002 file_filter = lambda f: input_api.FilterSourceFile(
2003 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532004 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2005 for line_num, line in fpath.ChangedContents():
2006 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022007 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532008 results.append(output_api.PresubmitError(
2009 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2010 (fpath.LocalPath(), line_num, deprecated_value, value)))
2011 return results
2012
mohan.reddyf21db962014-10-16 12:26:472013
dbeam070cfe62014-10-22 06:44:022014_DEPRECATED_JS = [
2015 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2016 ( "__defineGetter__", "Object.defineProperty" ),
2017 ( "__defineSetter__", "Object.defineProperty" ),
2018]
2019
dbeam1ec68ac2016-12-15 05:22:242020def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022021 """Make sure that we don't use deprecated JS in Chrome code."""
2022 results = []
2023 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2024 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2025 input_api.DEFAULT_BLACK_LIST)
2026 file_filter = lambda f: input_api.FilterSourceFile(
2027 f, white_list=file_inclusion_pattern, black_list=black_list)
2028 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2029 for lnum, line in fpath.ChangedContents():
2030 for (deprecated, replacement) in _DEPRECATED_JS:
2031 if deprecated in line:
2032 results.append(output_api.PresubmitError(
2033 "%s:%d: Use of deprecated JS %s, use %s instead" %
2034 (fpath.LocalPath(), lnum, deprecated, replacement)))
2035 return results
2036
2037
dbeam1ec68ac2016-12-15 05:22:242038def _CheckForRiskyJsFeatures(input_api, output_api):
2039 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2040 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2041
2042 arrow_lines = []
2043 for f in input_api.AffectedFiles(file_filter=file_filter):
2044 for lnum, line in f.ChangedContents():
2045 if ' => ' in line:
2046 arrow_lines.append((f.LocalPath(), lnum))
2047
2048 if not arrow_lines:
2049 return []
2050
2051 return [output_api.PresubmitPromptWarning("""
2052Use of => operator detected in:
2053%s
2054Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2055https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2056""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2057
2058
dgnaa68d5e2015-06-10 10:08:222059def _AndroidSpecificOnUploadChecks(input_api, output_api):
2060 """Groups checks that target android code."""
2061 results = []
dgnaa68d5e2015-06-10 10:08:222062 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222063 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292064 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422065 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222066 return results
2067
2068
[email protected]22c9bd72011-03-27 16:47:392069def _CommonChecks(input_api, output_api):
2070 """Checks common to both upload and commit."""
2071 results = []
2072 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382073 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542074 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582075 results.extend(
2076 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192077 results.extend(
[email protected]760deea2013-12-10 19:33:492078 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542079 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182080 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522081 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222082 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442083 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592084 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062085 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122086 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182087 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222088 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302089 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492090 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272091 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032092 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492093 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442094 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272095 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542096 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442097 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392098 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552099 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042100 results.extend(
2101 input_api.canned_checks.CheckChangeHasNoTabs(
2102 input_api,
2103 output_api,
2104 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402105 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162106 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592107 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082108 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242109 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2110 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472111 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042112 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232113 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432114 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242115 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402116 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152117 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172118 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502119 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242120 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242121
2122 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2123 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2124 input_api, output_api,
2125 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382126 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392127 return results
[email protected]1f7b4172010-01-28 01:17:342128
[email protected]b337cb5b2011-01-23 21:24:052129
[email protected]b8079ae4a2012-12-05 19:56:492130def _CheckPatchFiles(input_api, output_api):
2131 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2132 if f.LocalPath().endswith(('.orig', '.rej'))]
2133 if problems:
2134 return [output_api.PresubmitError(
2135 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032136 else:
2137 return []
[email protected]b8079ae4a2012-12-05 19:56:492138
2139
[email protected]b00342e7f2013-03-26 16:21:542140def _DidYouMeanOSMacro(bad_macro):
2141 try:
2142 return {'A': 'OS_ANDROID',
2143 'B': 'OS_BSD',
2144 'C': 'OS_CHROMEOS',
2145 'F': 'OS_FREEBSD',
2146 'L': 'OS_LINUX',
2147 'M': 'OS_MACOSX',
2148 'N': 'OS_NACL',
2149 'O': 'OS_OPENBSD',
2150 'P': 'OS_POSIX',
2151 'S': 'OS_SOLARIS',
2152 'W': 'OS_WIN'}[bad_macro[3].upper()]
2153 except KeyError:
2154 return ''
2155
2156
2157def _CheckForInvalidOSMacrosInFile(input_api, f):
2158 """Check for sensible looking, totally invalid OS macros."""
2159 preprocessor_statement = input_api.re.compile(r'^\s*#')
2160 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2161 results = []
2162 for lnum, line in f.ChangedContents():
2163 if preprocessor_statement.search(line):
2164 for match in os_macro.finditer(line):
2165 if not match.group(1) in _VALID_OS_MACROS:
2166 good = _DidYouMeanOSMacro(match.group(1))
2167 did_you_mean = ' (did you mean %s?)' % good if good else ''
2168 results.append(' %s:%d %s%s' % (f.LocalPath(),
2169 lnum,
2170 match.group(1),
2171 did_you_mean))
2172 return results
2173
2174
2175def _CheckForInvalidOSMacros(input_api, output_api):
2176 """Check all affected files for invalid OS macros."""
2177 bad_macros = []
2178 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472179 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542180 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2181
2182 if not bad_macros:
2183 return []
2184
2185 return [output_api.PresubmitError(
2186 'Possibly invalid OS macro[s] found. Please fix your code\n'
2187 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2188
lliabraa35bab3932014-10-01 12:16:442189
2190def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2191 """Check all affected files for invalid "if defined" macros."""
2192 ALWAYS_DEFINED_MACROS = (
2193 "TARGET_CPU_PPC",
2194 "TARGET_CPU_PPC64",
2195 "TARGET_CPU_68K",
2196 "TARGET_CPU_X86",
2197 "TARGET_CPU_ARM",
2198 "TARGET_CPU_MIPS",
2199 "TARGET_CPU_SPARC",
2200 "TARGET_CPU_ALPHA",
2201 "TARGET_IPHONE_SIMULATOR",
2202 "TARGET_OS_EMBEDDED",
2203 "TARGET_OS_IPHONE",
2204 "TARGET_OS_MAC",
2205 "TARGET_OS_UNIX",
2206 "TARGET_OS_WIN32",
2207 )
2208 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2209 results = []
2210 for lnum, line in f.ChangedContents():
2211 for match in ifdef_macro.finditer(line):
2212 if match.group(1) in ALWAYS_DEFINED_MACROS:
2213 always_defined = ' %s is always defined. ' % match.group(1)
2214 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2215 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2216 lnum,
2217 always_defined,
2218 did_you_mean))
2219 return results
2220
2221
2222def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2223 """Check all affected files for invalid "if defined" macros."""
2224 bad_macros = []
2225 for f in input_api.AffectedFiles():
2226 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2227 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2228
2229 if not bad_macros:
2230 return []
2231
2232 return [output_api.PresubmitError(
2233 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2234 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2235 bad_macros)]
2236
2237
mlamouria82272622014-09-16 18:45:042238def _CheckForIPCRules(input_api, output_api):
2239 """Check for same IPC rules described in
2240 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2241 """
2242 base_pattern = r'IPC_ENUM_TRAITS\('
2243 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2244 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2245
2246 problems = []
2247 for f in input_api.AffectedSourceFiles(None):
2248 local_path = f.LocalPath()
2249 if not local_path.endswith('.h'):
2250 continue
2251 for line_number, line in f.ChangedContents():
2252 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2253 problems.append(
2254 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2255
2256 if problems:
2257 return [output_api.PresubmitPromptWarning(
2258 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2259 else:
2260 return []
2261
[email protected]b00342e7f2013-03-26 16:21:542262
mostynbb639aca52015-01-07 20:31:232263def _CheckForWindowsLineEndings(input_api, output_api):
2264 """Check source code and known ascii text files for Windows style line
2265 endings.
2266 """
earthdok1b5e0ee2015-03-10 15:19:102267 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232268
2269 file_inclusion_pattern = (
2270 known_text_files,
2271 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2272 )
2273
2274 filter = lambda f: input_api.FilterSourceFile(
2275 f, white_list=file_inclusion_pattern, black_list=None)
2276 files = [f.LocalPath() for f in
2277 input_api.AffectedSourceFiles(filter)]
2278
2279 problems = []
2280
2281 for file in files:
2282 fp = open(file, 'r')
2283 for line in fp:
2284 if line.endswith('\r\n'):
2285 problems.append(file)
2286 break
2287 fp.close()
2288
2289 if problems:
2290 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2291 'these files to contain Windows style line endings?\n' +
2292 '\n'.join(problems))]
2293
2294 return []
2295
2296
pastarmovj89f7ee12016-09-20 14:58:132297def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2298 lint_filters=None, verbose_level=None):
2299 """Checks that all source files use SYSLOG properly."""
2300 syslog_files = []
2301 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562302 for line_number, line in f.ChangedContents():
2303 if 'SYSLOG' in line:
2304 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2305
pastarmovj89f7ee12016-09-20 14:58:132306 if syslog_files:
2307 return [output_api.PresubmitPromptWarning(
2308 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2309 ' calls.\nFiles to check:\n', items=syslog_files)]
2310 return []
2311
2312
[email protected]1f7b4172010-01-28 01:17:342313def CheckChangeOnUpload(input_api, output_api):
2314 results = []
2315 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472316 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282317 results.extend(
jam93a6ee792017-02-08 23:59:222318 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
2319 results.extend(
scottmg39b29952014-12-08 18:31:282320 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192321 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222322 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132323 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162324 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542325 return results
[email protected]ca8d1982009-02-19 16:33:122326
2327
[email protected]1bfb8322014-04-23 01:02:412328def GetTryServerMasterForBot(bot):
2329 """Returns the Try Server master for the given bot.
2330
[email protected]0bb112362014-07-26 04:38:322331 It tries to guess the master from the bot name, but may still fail
2332 and return None. There is no longer a default master.
2333 """
2334 # Potentially ambiguous bot names are listed explicitly.
2335 master_map = {
tandriie5587792016-07-14 00:34:502336 'chromium_presubmit': 'master.tryserver.chromium.linux',
2337 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412338 }
[email protected]0bb112362014-07-26 04:38:322339 master = master_map.get(bot)
2340 if not master:
wnwen4fbaab82016-05-25 12:54:362341 if 'android' in bot:
tandriie5587792016-07-14 00:34:502342 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362343 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502344 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322345 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502346 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322347 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502348 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322349 return master
[email protected]1bfb8322014-04-23 01:02:412350
2351
Paweł Hajdan, Jr55083782014-12-19 20:32:562352def GetDefaultTryConfigs(bots):
2353 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012354 """
2355
Paweł Hajdan, Jr55083782014-12-19 20:32:562356 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412357
2358 # Build up the mapping from tryserver master to bot/test.
2359 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562360 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412361 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2362 return out
[email protected]38c6a512013-12-18 23:48:012363
2364
[email protected]ca8d1982009-02-19 16:33:122365def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542366 results = []
[email protected]1f7b4172010-01-28 01:17:342367 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542368 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272369 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342370 input_api,
2371 output_api,
[email protected]2fdd1f362013-01-16 03:56:032372 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272373
jam93a6ee792017-02-08 23:59:222374 results.extend(
2375 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542376 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2377 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412378 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2379 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542380 return results