blob: 6334c053cab7c5eb75be523cda003b623f61af7c [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[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001194 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441195 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451196 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021197 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351198 r"dump_file_system.cc$",
1199 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401200 source_file_filter = lambda x: input_api.FilterSourceFile(
1201 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1202
1203 log_info = []
1204 printf = []
1205
1206 for f in input_api.AffectedSourceFiles(source_file_filter):
1207 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471208 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401209 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471210 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131211 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371212
mohan.reddyf21db962014-10-16 12:26:471213 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371214 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471215 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401216 printf.append(f.LocalPath())
1217
1218 if log_info:
1219 return [output_api.PresubmitError(
1220 'These files spam the console log with LOG(INFO):',
1221 items=log_info)]
1222 if printf:
1223 return [output_api.PresubmitError(
1224 'These files spam the console log with printf/fprintf:',
1225 items=printf)]
1226 return []
1227
1228
[email protected]49aa76a2013-12-04 06:59:161229def _CheckForAnonymousVariables(input_api, output_api):
1230 """These types are all expected to hold locks while in scope and
1231 so should never be anonymous (which causes them to be immediately
1232 destroyed)."""
1233 they_who_must_be_named = [
1234 'base::AutoLock',
1235 'base::AutoReset',
1236 'base::AutoUnlock',
1237 'SkAutoAlphaRestore',
1238 'SkAutoBitmapShaderInstall',
1239 'SkAutoBlitterChoose',
1240 'SkAutoBounderCommit',
1241 'SkAutoCallProc',
1242 'SkAutoCanvasRestore',
1243 'SkAutoCommentBlock',
1244 'SkAutoDescriptor',
1245 'SkAutoDisableDirectionCheck',
1246 'SkAutoDisableOvalCheck',
1247 'SkAutoFree',
1248 'SkAutoGlyphCache',
1249 'SkAutoHDC',
1250 'SkAutoLockColors',
1251 'SkAutoLockPixels',
1252 'SkAutoMalloc',
1253 'SkAutoMaskFreeImage',
1254 'SkAutoMutexAcquire',
1255 'SkAutoPathBoundsUpdate',
1256 'SkAutoPDFRelease',
1257 'SkAutoRasterClipValidate',
1258 'SkAutoRef',
1259 'SkAutoTime',
1260 'SkAutoTrace',
1261 'SkAutoUnref',
1262 ]
1263 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1264 # bad: base::AutoLock(lock.get());
1265 # not bad: base::AutoLock lock(lock.get());
1266 bad_pattern = input_api.re.compile(anonymous)
1267 # good: new base::AutoLock(lock.get())
1268 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1269 errors = []
1270
1271 for f in input_api.AffectedFiles():
1272 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1273 continue
1274 for linenum, line in f.ChangedContents():
1275 if bad_pattern.search(line) and not good_pattern.search(line):
1276 errors.append('%s:%d' % (f.LocalPath(), linenum))
1277
1278 if errors:
1279 return [output_api.PresubmitError(
1280 'These lines create anonymous variables that need to be named:',
1281 items=errors)]
1282 return []
1283
1284
[email protected]5fe0f8742013-11-29 01:04:591285def _CheckCygwinShell(input_api, output_api):
1286 source_file_filter = lambda x: input_api.FilterSourceFile(
1287 x, white_list=(r'.+\.(gyp|gypi)$',))
1288 cygwin_shell = []
1289
1290 for f in input_api.AffectedSourceFiles(source_file_filter):
1291 for linenum, line in f.ChangedContents():
1292 if 'msvs_cygwin_shell' in line:
1293 cygwin_shell.append(f.LocalPath())
1294 break
1295
1296 if cygwin_shell:
1297 return [output_api.PresubmitError(
1298 'These files should not use msvs_cygwin_shell (the default is 0):',
1299 items=cygwin_shell)]
1300 return []
1301
[email protected]85218562013-11-22 07:41:401302
[email protected]999261d2014-03-03 20:08:081303def _CheckUserActionUpdate(input_api, output_api):
1304 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521305 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081306 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521307 # If actions.xml is already included in the changelist, the PRESUBMIT
1308 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081309 return []
1310
[email protected]999261d2014-03-03 20:08:081311 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1312 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521313 current_actions = None
[email protected]999261d2014-03-03 20:08:081314 for f in input_api.AffectedFiles(file_filter=file_filter):
1315 for line_num, line in f.ChangedContents():
1316 match = input_api.re.search(action_re, line)
1317 if match:
[email protected]2f92dec2014-03-07 19:21:521318 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1319 # loaded only once.
1320 if not current_actions:
1321 with open('tools/metrics/actions/actions.xml') as actions_f:
1322 current_actions = actions_f.read()
1323 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081324 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521325 action = 'name="{0}"'.format(action_name)
1326 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081327 return [output_api.PresubmitPromptWarning(
1328 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521329 'tools/metrics/actions/actions.xml. Please run '
1330 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081331 % (f.LocalPath(), line_num, action_name))]
1332 return []
1333
1334
[email protected]99171a92014-06-03 08:44:471335def _GetJSONParseError(input_api, filename, eat_comments=True):
1336 try:
1337 contents = input_api.ReadFile(filename)
1338 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131339 import sys
1340 original_sys_path = sys.path
1341 try:
1342 sys.path = sys.path + [input_api.os_path.join(
1343 input_api.PresubmitLocalPath(),
1344 'tools', 'json_comment_eater')]
1345 import json_comment_eater
1346 finally:
1347 sys.path = original_sys_path
1348 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471349
1350 input_api.json.loads(contents)
1351 except ValueError as e:
1352 return e
1353 return None
1354
1355
1356def _GetIDLParseError(input_api, filename):
1357 try:
1358 contents = input_api.ReadFile(filename)
1359 idl_schema = input_api.os_path.join(
1360 input_api.PresubmitLocalPath(),
1361 'tools', 'json_schema_compiler', 'idl_schema.py')
1362 process = input_api.subprocess.Popen(
1363 [input_api.python_executable, idl_schema],
1364 stdin=input_api.subprocess.PIPE,
1365 stdout=input_api.subprocess.PIPE,
1366 stderr=input_api.subprocess.PIPE,
1367 universal_newlines=True)
1368 (_, error) = process.communicate(input=contents)
1369 return error or None
1370 except ValueError as e:
1371 return e
1372
1373
1374def _CheckParseErrors(input_api, output_api):
1375 """Check that IDL and JSON files do not contain syntax errors."""
1376 actions = {
1377 '.idl': _GetIDLParseError,
1378 '.json': _GetJSONParseError,
1379 }
1380 # These paths contain test data and other known invalid JSON files.
1381 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491382 r'test[\\\/]data[\\\/]',
1383 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471384 ]
1385 # Most JSON files are preprocessed and support comments, but these do not.
1386 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491387 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471388 ]
1389 # Only run IDL checker on files in these directories.
1390 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491391 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1392 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471393 ]
1394
1395 def get_action(affected_file):
1396 filename = affected_file.LocalPath()
1397 return actions.get(input_api.os_path.splitext(filename)[1])
1398
1399 def MatchesFile(patterns, path):
1400 for pattern in patterns:
1401 if input_api.re.search(pattern, path):
1402 return True
1403 return False
1404
1405 def FilterFile(affected_file):
1406 action = get_action(affected_file)
1407 if not action:
1408 return False
1409 path = affected_file.LocalPath()
1410
1411 if MatchesFile(excluded_patterns, path):
1412 return False
1413
1414 if (action == _GetIDLParseError and
1415 not MatchesFile(idl_included_patterns, path)):
1416 return False
1417 return True
1418
1419 results = []
1420 for affected_file in input_api.AffectedFiles(
1421 file_filter=FilterFile, include_deletes=False):
1422 action = get_action(affected_file)
1423 kwargs = {}
1424 if (action == _GetJSONParseError and
1425 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1426 kwargs['eat_comments'] = False
1427 parse_error = action(input_api,
1428 affected_file.AbsoluteLocalPath(),
1429 **kwargs)
1430 if parse_error:
1431 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1432 (affected_file.LocalPath(), parse_error)))
1433 return results
1434
1435
[email protected]760deea2013-12-10 19:33:491436def _CheckJavaStyle(input_api, output_api):
1437 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471438 import sys
[email protected]760deea2013-12-10 19:33:491439 original_sys_path = sys.path
1440 try:
1441 sys.path = sys.path + [input_api.os_path.join(
1442 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1443 import checkstyle
1444 finally:
1445 # Restore sys.path to what it was before.
1446 sys.path = original_sys_path
1447
1448 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091449 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511450 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491451
1452
dchenge07de812016-06-20 19:27:171453def _CheckIpcOwners(input_api, output_api):
1454 """Checks that affected files involving IPC have an IPC OWNERS rule.
1455
1456 Whether or not a file affects IPC is determined by a simple whitelist of
1457 filename patterns."""
1458 file_patterns = [
palmerb19a0932017-01-24 04:00:311459 # Legacy IPC:
dchenge07de812016-06-20 19:27:171460 '*_messages.cc',
1461 '*_messages*.h',
1462 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311463 # Mojo IPC:
dchenge07de812016-06-20 19:27:171464 '*.mojom',
1465 '*_struct_traits*.*',
1466 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311467 '*.typemap',
1468 # Android native IPC:
1469 '*.aidl',
1470 # Blink uses a different file naming convention:
1471 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171472 '*StructTraits*.*',
1473 '*TypeConverter*.*',
1474 ]
1475
scottmg7a6ed5ba2016-11-04 18:22:041476 # These third_party directories do not contain IPCs, but contain files
1477 # matching the above patterns, which trigger false positives.
1478 exclude_paths = [
1479 'third_party/crashpad/*',
1480 ]
1481
dchenge07de812016-06-20 19:27:171482 # Dictionary mapping an OWNERS file path to Patterns.
1483 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1484 # rules ) to a PatternEntry.
1485 # PatternEntry is a dictionary with two keys:
1486 # - 'files': the files that are matched by this pattern
1487 # - 'rules': the per-file rules needed for this pattern
1488 # For example, if we expect OWNERS file to contain rules for *.mojom and
1489 # *_struct_traits*.*, Patterns might look like this:
1490 # {
1491 # '*.mojom': {
1492 # 'files': ...,
1493 # 'rules': [
1494 # 'per-file *.mojom=set noparent',
1495 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1496 # ],
1497 # },
1498 # '*_struct_traits*.*': {
1499 # 'files': ...,
1500 # 'rules': [
1501 # 'per-file *_struct_traits*.*=set noparent',
1502 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1503 # ],
1504 # },
1505 # }
1506 to_check = {}
1507
1508 # Iterate through the affected files to see what we actually need to check
1509 # for. We should only nag patch authors about per-file rules if a file in that
1510 # directory would match that pattern. If a directory only contains *.mojom
1511 # files and no *_messages*.h files, we should only nag about rules for
1512 # *.mojom files.
rockot51249332016-06-23 16:32:251513 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171514 for pattern in file_patterns:
1515 if input_api.fnmatch.fnmatch(
1516 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041517 skip = False
1518 for exclude in exclude_paths:
1519 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1520 skip = True
1521 break
1522 if skip:
1523 continue
dchenge07de812016-06-20 19:27:171524 owners_file = input_api.os_path.join(
1525 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1526 if owners_file not in to_check:
1527 to_check[owners_file] = {}
1528 if pattern not in to_check[owners_file]:
1529 to_check[owners_file][pattern] = {
1530 'files': [],
1531 'rules': [
1532 'per-file %s=set noparent' % pattern,
1533 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1534 ]
1535 }
1536 to_check[owners_file][pattern]['files'].append(f)
1537 break
1538
1539 # Now go through the OWNERS files we collected, filtering out rules that are
1540 # already present in that OWNERS file.
1541 for owners_file, patterns in to_check.iteritems():
1542 try:
1543 with file(owners_file) as f:
1544 lines = set(f.read().splitlines())
1545 for entry in patterns.itervalues():
1546 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1547 ]
1548 except IOError:
1549 # No OWNERS file, so all the rules are definitely missing.
1550 continue
1551
1552 # All the remaining lines weren't found in OWNERS files, so emit an error.
1553 errors = []
1554 for owners_file, patterns in to_check.iteritems():
1555 missing_lines = []
1556 files = []
1557 for pattern, entry in patterns.iteritems():
1558 missing_lines.extend(entry['rules'])
1559 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1560 if missing_lines:
1561 errors.append(
1562 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1563 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1564
1565 results = []
1566 if errors:
vabrf5ce3bf92016-07-11 14:52:411567 if input_api.is_committing:
1568 output = output_api.PresubmitError
1569 else:
1570 output = output_api.PresubmitPromptWarning
1571 results.append(output(
dchenge07de812016-06-20 19:27:171572 'Found changes to IPC files without a security OWNER!',
1573 long_text='\n\n'.join(errors)))
1574
1575 return results
1576
1577
jbriance9e12f162016-11-25 07:57:501578def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311579 """Checks that added or removed lines in non third party affected
1580 header files do not lead to new useless class or struct forward
1581 declaration.
jbriance9e12f162016-11-25 07:57:501582 """
1583 results = []
1584 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1585 input_api.re.MULTILINE)
1586 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1587 input_api.re.MULTILINE)
1588 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311589 if (f.LocalPath().startswith('third_party') and
1590 not f.LocalPath().startswith('third_party/WebKit') and
1591 not f.LocalPath().startswith('third_party\\WebKit')):
1592 continue
1593
jbriance9e12f162016-11-25 07:57:501594 if not f.LocalPath().endswith('.h'):
1595 continue
1596
1597 contents = input_api.ReadFile(f)
1598 fwd_decls = input_api.re.findall(class_pattern, contents)
1599 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1600
1601 useless_fwd_decls = []
1602 for decl in fwd_decls:
1603 count = sum(1 for _ in input_api.re.finditer(
1604 r'\b%s\b' % input_api.re.escape(decl), contents))
1605 if count == 1:
1606 useless_fwd_decls.append(decl)
1607
1608 if not useless_fwd_decls:
1609 continue
1610
1611 for line in f.GenerateScmDiff().splitlines():
1612 if (line.startswith('-') and not line.startswith('--') or
1613 line.startswith('+') and not line.startswith('++')):
1614 for decl in useless_fwd_decls:
1615 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1616 results.append(output_api.PresubmitPromptWarning(
1617 '%s: %s forward declaration is becoming useless' %
1618 (f.LocalPath(), decl)))
1619 useless_fwd_decls.remove(decl)
1620
1621 return results
1622
1623
dskiba88634f4e2015-08-14 23:03:291624def _CheckAndroidToastUsage(input_api, output_api):
1625 """Checks that code uses org.chromium.ui.widget.Toast instead of
1626 android.widget.Toast (Chromium Toast doesn't force hardware
1627 acceleration on low-end devices, saving memory).
1628 """
1629 toast_import_pattern = input_api.re.compile(
1630 r'^import android\.widget\.Toast;$')
1631
1632 errors = []
1633
1634 sources = lambda affected_file: input_api.FilterSourceFile(
1635 affected_file,
1636 black_list=(_EXCLUDED_PATHS +
1637 _TEST_CODE_EXCLUDED_PATHS +
1638 input_api.DEFAULT_BLACK_LIST +
1639 (r'^chromecast[\\\/].*',
1640 r'^remoting[\\\/].*')),
1641 white_list=(r'.*\.java$',))
1642
1643 for f in input_api.AffectedSourceFiles(sources):
1644 for line_num, line in f.ChangedContents():
1645 if toast_import_pattern.search(line):
1646 errors.append("%s:%d" % (f.LocalPath(), line_num))
1647
1648 results = []
1649
1650 if errors:
1651 results.append(output_api.PresubmitError(
1652 'android.widget.Toast usage is detected. Android toasts use hardware'
1653 ' acceleration, and can be\ncostly on low-end devices. Please use'
1654 ' org.chromium.ui.widget.Toast instead.\n'
1655 'Contact [email protected] if you have any questions.',
1656 errors))
1657
1658 return results
1659
1660
dgnaa68d5e2015-06-10 10:08:221661def _CheckAndroidCrLogUsage(input_api, output_api):
1662 """Checks that new logs using org.chromium.base.Log:
1663 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511664 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221665 """
pkotwicza1dd0b002016-05-16 14:41:041666
1667 # Do not check format of logs in //chrome/android/webapk because
1668 # //chrome/android/webapk cannot depend on //base
1669 cr_log_check_excluded_paths = [
1670 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1671 ]
1672
dgnaa68d5e2015-06-10 10:08:221673 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121674 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1675 class_in_base_pattern = input_api.re.compile(
1676 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1677 has_some_log_import_pattern = input_api.re.compile(
1678 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221679 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121680 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221681 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511682 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221683 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221684
Vincent Scheib16d7b272015-09-15 18:09:071685 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221686 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041687 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1688 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121689
dgnaa68d5e2015-06-10 10:08:221690 tag_decl_errors = []
1691 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121692 tag_errors = []
dgn38736db2015-09-18 19:20:511693 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121694 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221695
1696 for f in input_api.AffectedSourceFiles(sources):
1697 file_content = input_api.ReadFile(f)
1698 has_modified_logs = False
1699
1700 # Per line checks
dgn87d9fb62015-06-12 09:15:121701 if (cr_log_import_pattern.search(file_content) or
1702 (class_in_base_pattern.search(file_content) and
1703 not has_some_log_import_pattern.search(file_content))):
1704 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221705 for line_num, line in f.ChangedContents():
1706
1707 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121708 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221709 if match:
1710 has_modified_logs = True
1711
1712 # Make sure it uses "TAG"
1713 if not match.group('tag') == 'TAG':
1714 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121715 else:
1716 # Report non cr Log function calls in changed lines
1717 for line_num, line in f.ChangedContents():
1718 if log_call_pattern.search(line):
1719 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221720
1721 # Per file checks
1722 if has_modified_logs:
1723 # Make sure the tag is using the "cr" prefix and is not too long
1724 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511725 tag_name = match.group('name') if match else None
1726 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221727 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511728 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221729 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511730 elif '.' in tag_name:
1731 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221732
1733 results = []
1734 if tag_decl_errors:
1735 results.append(output_api.PresubmitPromptWarning(
1736 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511737 '"private static final String TAG = "<package tag>".\n'
1738 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221739 tag_decl_errors))
1740
1741 if tag_length_errors:
1742 results.append(output_api.PresubmitError(
1743 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511744 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221745 tag_length_errors))
1746
1747 if tag_errors:
1748 results.append(output_api.PresubmitPromptWarning(
1749 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1750 tag_errors))
1751
dgn87d9fb62015-06-12 09:15:121752 if util_log_errors:
dgn4401aa52015-04-29 16:26:171753 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121754 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1755 util_log_errors))
1756
dgn38736db2015-09-18 19:20:511757 if tag_with_dot_errors:
1758 results.append(output_api.PresubmitPromptWarning(
1759 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1760 tag_with_dot_errors))
1761
dgn4401aa52015-04-29 16:26:171762 return results
1763
1764
yolandyan45001472016-12-21 21:12:421765def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1766 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1767 deprecated_annotation_import_pattern = input_api.re.compile(
1768 r'^import android\.test\.suitebuilder\.annotation\..*;',
1769 input_api.re.MULTILINE)
1770 sources = lambda x: input_api.FilterSourceFile(
1771 x, white_list=(r'.*\.java$',), black_list=None)
1772 errors = []
1773 for f in input_api.AffectedFiles(sources):
1774 for line_num, line in f.ChangedContents():
1775 if deprecated_annotation_import_pattern.search(line):
1776 errors.append("%s:%d" % (f.LocalPath(), line_num))
1777
1778 results = []
1779 if errors:
1780 results.append(output_api.PresubmitError(
1781 'Annotations in android.test.suitebuilder.annotation have been'
1782 ' deprecated since API level 24. Please use android.support.test.filters'
1783 ' from //third_party/android_support_test_runner:runner_java instead.'
1784 ' Contact [email protected] if you have any questions.', errors))
1785 return results
1786
1787
agrieve7b6479d82015-10-07 14:24:221788def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1789 """Checks if MDPI assets are placed in a correct directory."""
1790 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1791 ('/res/drawable/' in f.LocalPath() or
1792 '/res/drawable-ldrtl/' in f.LocalPath()))
1793 errors = []
1794 for f in input_api.AffectedFiles(include_deletes=False,
1795 file_filter=file_filter):
1796 errors.append(' %s' % f.LocalPath())
1797
1798 results = []
1799 if errors:
1800 results.append(output_api.PresubmitError(
1801 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1802 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1803 '/res/drawable-ldrtl/.\n'
1804 'Contact [email protected] if you have questions.', errors))
1805 return results
1806
1807
agrievef32bcc72016-04-04 14:57:401808class PydepsChecker(object):
1809 def __init__(self, input_api, pydeps_files):
1810 self._file_cache = {}
1811 self._input_api = input_api
1812 self._pydeps_files = pydeps_files
1813
1814 def _LoadFile(self, path):
1815 """Returns the list of paths within a .pydeps file relative to //."""
1816 if path not in self._file_cache:
1817 with open(path) as f:
1818 self._file_cache[path] = f.read()
1819 return self._file_cache[path]
1820
1821 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1822 """Returns an interable of paths within the .pydep, relativized to //."""
1823 os_path = self._input_api.os_path
1824 pydeps_dir = os_path.dirname(pydeps_path)
1825 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1826 if not l.startswith('*'))
1827 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1828
1829 def _CreateFilesToPydepsMap(self):
1830 """Returns a map of local_path -> list_of_pydeps."""
1831 ret = {}
1832 for pydep_local_path in self._pydeps_files:
1833 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1834 ret.setdefault(path, []).append(pydep_local_path)
1835 return ret
1836
1837 def ComputeAffectedPydeps(self):
1838 """Returns an iterable of .pydeps files that might need regenerating."""
1839 affected_pydeps = set()
1840 file_to_pydeps_map = None
1841 for f in self._input_api.AffectedFiles(include_deletes=True):
1842 local_path = f.LocalPath()
1843 if local_path == 'DEPS':
1844 return self._pydeps_files
1845 elif local_path.endswith('.pydeps'):
1846 if local_path in self._pydeps_files:
1847 affected_pydeps.add(local_path)
1848 elif local_path.endswith('.py'):
1849 if file_to_pydeps_map is None:
1850 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1851 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1852 return affected_pydeps
1853
1854 def DetermineIfStale(self, pydeps_path):
1855 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411856 import difflib
agrievef32bcc72016-04-04 14:57:401857 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1858 cmd = old_pydeps_data[1][1:].strip()
1859 new_pydeps_data = self._input_api.subprocess.check_output(
1860 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411861 old_contents = old_pydeps_data[2:]
1862 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401863 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411864 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401865
1866
1867def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1868 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001869 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281870 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1871 # Mac, so skip it on other platforms.
1872 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001873 return []
agrievef32bcc72016-04-04 14:57:401874 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1875 is_android = input_api.os_path.exists('third_party/android_tools')
1876 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1877 results = []
1878 # First, check for new / deleted .pydeps.
1879 for f in input_api.AffectedFiles(include_deletes=True):
1880 if f.LocalPath().endswith('.pydeps'):
1881 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1882 results.append(output_api.PresubmitError(
1883 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1884 'remove %s' % f.LocalPath()))
1885 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1886 results.append(output_api.PresubmitError(
1887 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1888 'include %s' % f.LocalPath()))
1889
1890 if results:
1891 return results
1892
1893 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1894
1895 for pydep_path in checker.ComputeAffectedPydeps():
1896 try:
phajdan.jr0d9878552016-11-04 10:49:411897 result = checker.DetermineIfStale(pydep_path)
1898 if result:
1899 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401900 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411901 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1902 'To regenerate, run:\n\n %s' %
1903 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401904 except input_api.subprocess.CalledProcessError as error:
1905 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1906 long_text=error.output)]
1907
1908 return results
1909
1910
glidere61efad2015-02-18 17:39:431911def _CheckSingletonInHeaders(input_api, output_api):
1912 """Checks to make sure no header files have |Singleton<|."""
1913 def FileFilter(affected_file):
1914 # It's ok for base/memory/singleton.h to have |Singleton<|.
1915 black_list = (_EXCLUDED_PATHS +
1916 input_api.DEFAULT_BLACK_LIST +
1917 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1918 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1919
sergeyu34d21222015-09-16 00:11:441920 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431921 files = []
1922 for f in input_api.AffectedSourceFiles(FileFilter):
1923 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1924 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1925 contents = input_api.ReadFile(f)
1926 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241927 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431928 pattern.search(line)):
1929 files.append(f)
1930 break
1931
1932 if files:
yolandyandaabc6d2016-04-18 18:29:391933 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441934 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431935 'Please move them to an appropriate source file so that the ' +
1936 'template gets instantiated in a single compilation unit.',
1937 files) ]
1938 return []
1939
1940
dbeam1ec68ac2016-12-15 05:22:241941def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:201942 """Checks for old style compiled_resources.gyp files."""
1943 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1944
1945 added_compiled_resources = filter(is_compiled_resource, [
1946 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1947 ])
1948
1949 if not added_compiled_resources:
1950 return []
1951
1952 return [output_api.PresubmitError(
1953 "Found new compiled_resources.gyp files:\n%s\n\n"
1954 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551955 "please use compiled_resources2.gyp instead:\n"
1956 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1957 %
dbeam37e8e7402016-02-10 22:58:201958 "\n".join(added_compiled_resources))]
1959
1960
[email protected]fd20b902014-05-09 02:14:531961_DEPRECATED_CSS = [
1962 # Values
1963 ( "-webkit-box", "flex" ),
1964 ( "-webkit-inline-box", "inline-flex" ),
1965 ( "-webkit-flex", "flex" ),
1966 ( "-webkit-inline-flex", "inline-flex" ),
1967 ( "-webkit-min-content", "min-content" ),
1968 ( "-webkit-max-content", "max-content" ),
1969
1970 # Properties
1971 ( "-webkit-background-clip", "background-clip" ),
1972 ( "-webkit-background-origin", "background-origin" ),
1973 ( "-webkit-background-size", "background-size" ),
1974 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441975 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531976
1977 # Functions
1978 ( "-webkit-gradient", "gradient" ),
1979 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1980 ( "-webkit-linear-gradient", "linear-gradient" ),
1981 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1982 ( "-webkit-radial-gradient", "radial-gradient" ),
1983 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1984]
1985
dbeam1ec68ac2016-12-15 05:22:241986def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531987 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251988 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341989 documentation and iOS CSS for dom distiller
1990 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251991 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531992 results = []
dbeam070cfe62014-10-22 06:44:021993 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251994 black_list = (_EXCLUDED_PATHS +
1995 _TEST_CODE_EXCLUDED_PATHS +
1996 input_api.DEFAULT_BLACK_LIST +
1997 (r"^chrome/common/extensions/docs",
1998 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341999 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052000 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442001 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252002 r"^native_client_sdk"))
2003 file_filter = lambda f: input_api.FilterSourceFile(
2004 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532005 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2006 for line_num, line in fpath.ChangedContents():
2007 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022008 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532009 results.append(output_api.PresubmitError(
2010 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2011 (fpath.LocalPath(), line_num, deprecated_value, value)))
2012 return results
2013
mohan.reddyf21db962014-10-16 12:26:472014
dbeam070cfe62014-10-22 06:44:022015_DEPRECATED_JS = [
2016 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2017 ( "__defineGetter__", "Object.defineProperty" ),
2018 ( "__defineSetter__", "Object.defineProperty" ),
2019]
2020
dbeam1ec68ac2016-12-15 05:22:242021def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022022 """Make sure that we don't use deprecated JS in Chrome code."""
2023 results = []
2024 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2025 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2026 input_api.DEFAULT_BLACK_LIST)
2027 file_filter = lambda f: input_api.FilterSourceFile(
2028 f, white_list=file_inclusion_pattern, black_list=black_list)
2029 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2030 for lnum, line in fpath.ChangedContents():
2031 for (deprecated, replacement) in _DEPRECATED_JS:
2032 if deprecated in line:
2033 results.append(output_api.PresubmitError(
2034 "%s:%d: Use of deprecated JS %s, use %s instead" %
2035 (fpath.LocalPath(), lnum, deprecated, replacement)))
2036 return results
2037
2038
dbeam1ec68ac2016-12-15 05:22:242039def _CheckForRiskyJsFeatures(input_api, output_api):
2040 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2041 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2042
2043 arrow_lines = []
2044 for f in input_api.AffectedFiles(file_filter=file_filter):
2045 for lnum, line in f.ChangedContents():
2046 if ' => ' in line:
2047 arrow_lines.append((f.LocalPath(), lnum))
2048
2049 if not arrow_lines:
2050 return []
2051
2052 return [output_api.PresubmitPromptWarning("""
2053Use of => operator detected in:
2054%s
2055Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2056https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2057""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2058
2059
dgnaa68d5e2015-06-10 10:08:222060def _AndroidSpecificOnUploadChecks(input_api, output_api):
2061 """Groups checks that target android code."""
2062 results = []
dgnaa68d5e2015-06-10 10:08:222063 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222064 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292065 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422066 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222067 return results
2068
2069
[email protected]22c9bd72011-03-27 16:47:392070def _CommonChecks(input_api, output_api):
2071 """Checks common to both upload and commit."""
2072 results = []
2073 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382074 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542075 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582076 results.extend(
2077 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192078 results.extend(
[email protected]760deea2013-12-10 19:33:492079 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542080 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182081 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522082 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222083 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442084 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592085 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062086 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122087 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182088 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222089 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302090 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492091 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272092 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032093 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492094 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442095 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272096 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542097 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442098 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392099 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552100 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042101 results.extend(
2102 input_api.canned_checks.CheckChangeHasNoTabs(
2103 input_api,
2104 output_api,
2105 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402106 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162107 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592108 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082109 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242110 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2111 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472112 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042113 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232114 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432115 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242116 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402117 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152118 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172119 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502120 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242121 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242122
2123 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2124 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2125 input_api, output_api,
2126 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382127 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392128 return results
[email protected]1f7b4172010-01-28 01:17:342129
[email protected]b337cb5b2011-01-23 21:24:052130
[email protected]b8079ae4a2012-12-05 19:56:492131def _CheckPatchFiles(input_api, output_api):
2132 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2133 if f.LocalPath().endswith(('.orig', '.rej'))]
2134 if problems:
2135 return [output_api.PresubmitError(
2136 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032137 else:
2138 return []
[email protected]b8079ae4a2012-12-05 19:56:492139
2140
[email protected]b00342e7f2013-03-26 16:21:542141def _DidYouMeanOSMacro(bad_macro):
2142 try:
2143 return {'A': 'OS_ANDROID',
2144 'B': 'OS_BSD',
2145 'C': 'OS_CHROMEOS',
2146 'F': 'OS_FREEBSD',
2147 'L': 'OS_LINUX',
2148 'M': 'OS_MACOSX',
2149 'N': 'OS_NACL',
2150 'O': 'OS_OPENBSD',
2151 'P': 'OS_POSIX',
2152 'S': 'OS_SOLARIS',
2153 'W': 'OS_WIN'}[bad_macro[3].upper()]
2154 except KeyError:
2155 return ''
2156
2157
2158def _CheckForInvalidOSMacrosInFile(input_api, f):
2159 """Check for sensible looking, totally invalid OS macros."""
2160 preprocessor_statement = input_api.re.compile(r'^\s*#')
2161 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2162 results = []
2163 for lnum, line in f.ChangedContents():
2164 if preprocessor_statement.search(line):
2165 for match in os_macro.finditer(line):
2166 if not match.group(1) in _VALID_OS_MACROS:
2167 good = _DidYouMeanOSMacro(match.group(1))
2168 did_you_mean = ' (did you mean %s?)' % good if good else ''
2169 results.append(' %s:%d %s%s' % (f.LocalPath(),
2170 lnum,
2171 match.group(1),
2172 did_you_mean))
2173 return results
2174
2175
2176def _CheckForInvalidOSMacros(input_api, output_api):
2177 """Check all affected files for invalid OS macros."""
2178 bad_macros = []
2179 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472180 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542181 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2182
2183 if not bad_macros:
2184 return []
2185
2186 return [output_api.PresubmitError(
2187 'Possibly invalid OS macro[s] found. Please fix your code\n'
2188 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2189
lliabraa35bab3932014-10-01 12:16:442190
2191def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2192 """Check all affected files for invalid "if defined" macros."""
2193 ALWAYS_DEFINED_MACROS = (
2194 "TARGET_CPU_PPC",
2195 "TARGET_CPU_PPC64",
2196 "TARGET_CPU_68K",
2197 "TARGET_CPU_X86",
2198 "TARGET_CPU_ARM",
2199 "TARGET_CPU_MIPS",
2200 "TARGET_CPU_SPARC",
2201 "TARGET_CPU_ALPHA",
2202 "TARGET_IPHONE_SIMULATOR",
2203 "TARGET_OS_EMBEDDED",
2204 "TARGET_OS_IPHONE",
2205 "TARGET_OS_MAC",
2206 "TARGET_OS_UNIX",
2207 "TARGET_OS_WIN32",
2208 )
2209 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2210 results = []
2211 for lnum, line in f.ChangedContents():
2212 for match in ifdef_macro.finditer(line):
2213 if match.group(1) in ALWAYS_DEFINED_MACROS:
2214 always_defined = ' %s is always defined. ' % match.group(1)
2215 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2216 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2217 lnum,
2218 always_defined,
2219 did_you_mean))
2220 return results
2221
2222
2223def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2224 """Check all affected files for invalid "if defined" macros."""
2225 bad_macros = []
2226 for f in input_api.AffectedFiles():
2227 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2228 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2229
2230 if not bad_macros:
2231 return []
2232
2233 return [output_api.PresubmitError(
2234 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2235 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2236 bad_macros)]
2237
2238
mlamouria82272622014-09-16 18:45:042239def _CheckForIPCRules(input_api, output_api):
2240 """Check for same IPC rules described in
2241 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2242 """
2243 base_pattern = r'IPC_ENUM_TRAITS\('
2244 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2245 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2246
2247 problems = []
2248 for f in input_api.AffectedSourceFiles(None):
2249 local_path = f.LocalPath()
2250 if not local_path.endswith('.h'):
2251 continue
2252 for line_number, line in f.ChangedContents():
2253 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2254 problems.append(
2255 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2256
2257 if problems:
2258 return [output_api.PresubmitPromptWarning(
2259 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2260 else:
2261 return []
2262
[email protected]b00342e7f2013-03-26 16:21:542263
mostynbb639aca52015-01-07 20:31:232264def _CheckForWindowsLineEndings(input_api, output_api):
2265 """Check source code and known ascii text files for Windows style line
2266 endings.
2267 """
earthdok1b5e0ee2015-03-10 15:19:102268 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232269
2270 file_inclusion_pattern = (
2271 known_text_files,
2272 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2273 )
2274
2275 filter = lambda f: input_api.FilterSourceFile(
2276 f, white_list=file_inclusion_pattern, black_list=None)
2277 files = [f.LocalPath() for f in
2278 input_api.AffectedSourceFiles(filter)]
2279
2280 problems = []
2281
2282 for file in files:
2283 fp = open(file, 'r')
2284 for line in fp:
2285 if line.endswith('\r\n'):
2286 problems.append(file)
2287 break
2288 fp.close()
2289
2290 if problems:
2291 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2292 'these files to contain Windows style line endings?\n' +
2293 '\n'.join(problems))]
2294
2295 return []
2296
2297
pastarmovj89f7ee12016-09-20 14:58:132298def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2299 lint_filters=None, verbose_level=None):
2300 """Checks that all source files use SYSLOG properly."""
2301 syslog_files = []
2302 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562303 for line_number, line in f.ChangedContents():
2304 if 'SYSLOG' in line:
2305 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2306
pastarmovj89f7ee12016-09-20 14:58:132307 if syslog_files:
2308 return [output_api.PresubmitPromptWarning(
2309 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2310 ' calls.\nFiles to check:\n', items=syslog_files)]
2311 return []
2312
2313
[email protected]1f7b4172010-01-28 01:17:342314def CheckChangeOnUpload(input_api, output_api):
2315 results = []
2316 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472317 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282318 results.extend(
jam93a6ee792017-02-08 23:59:222319 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
2320 results.extend(
scottmg39b29952014-12-08 18:31:282321 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192322 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222323 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132324 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162325 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542326 return results
[email protected]ca8d1982009-02-19 16:33:122327
2328
[email protected]1bfb8322014-04-23 01:02:412329def GetTryServerMasterForBot(bot):
2330 """Returns the Try Server master for the given bot.
2331
[email protected]0bb112362014-07-26 04:38:322332 It tries to guess the master from the bot name, but may still fail
2333 and return None. There is no longer a default master.
2334 """
2335 # Potentially ambiguous bot names are listed explicitly.
2336 master_map = {
tandriie5587792016-07-14 00:34:502337 'chromium_presubmit': 'master.tryserver.chromium.linux',
2338 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412339 }
[email protected]0bb112362014-07-26 04:38:322340 master = master_map.get(bot)
2341 if not master:
wnwen4fbaab82016-05-25 12:54:362342 if 'android' in bot:
tandriie5587792016-07-14 00:34:502343 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362344 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502345 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322346 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502347 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322348 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502349 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322350 return master
[email protected]1bfb8322014-04-23 01:02:412351
2352
Paweł Hajdan, Jr55083782014-12-19 20:32:562353def GetDefaultTryConfigs(bots):
2354 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012355 """
2356
Paweł Hajdan, Jr55083782014-12-19 20:32:562357 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412358
2359 # Build up the mapping from tryserver master to bot/test.
2360 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562361 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412362 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2363 return out
[email protected]38c6a512013-12-18 23:48:012364
2365
[email protected]ca8d1982009-02-19 16:33:122366def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542367 results = []
[email protected]1f7b4172010-01-28 01:17:342368 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542369 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272370 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342371 input_api,
2372 output_api,
[email protected]2fdd1f362013-01-16 03:56:032373 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272374
jam93a6ee792017-02-08 23:59:222375 results.extend(
2376 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542377 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2378 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412379 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2380 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542381 return results