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