blob: 8ce0185bc7c8c36016377211a93bca7b08fdff30 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
vapierb2053f542017-03-09 19:46:1028 r"tools[\\\/]md_browser[\\\/].*\.css$",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5344 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4750 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4951 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0852 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4953 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4454)
[email protected]ca8d1982009-02-19 16:33:1255
wnwenbdc444e2016-05-25 13:44:1556
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2166 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
67 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
wnwenbdc444e2016-05-25 13:44:1569
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
jif65398702016-10-27 10:19:48143 (
144 r"/\s+UTF8String\s*]",
145 (
146 'The use of -[NSString UTF8String] is dangerous as it can return null',
147 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
148 'Please use |SysNSStringToUTF8| instead.',
149 ),
150 True,
151 ),
[email protected]127f18ec2012-06-16 05:05:59152)
153
154
155_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20156 # Make sure that gtest's FRIEND_TEST() macro is not used; the
157 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30158 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20159 (
160 'FRIEND_TEST(',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20163 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
164 ),
165 False,
[email protected]7345da02012-11-27 14:31:49166 (),
[email protected]23e6cbc2012-06-16 18:51:20167 ),
168 (
thomasanderson4b569052016-09-14 20:15:53169 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
170 (
171 'Chrome clients wishing to select events on X windows should use',
172 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
173 'you are selecting events from the GPU process, or if you are using',
174 'an XDisplay other than gfx::GetXDisplay().',
175 ),
176 True,
177 (
178 r"^ui[\\\/]gl[\\\/].*\.cc$",
179 r"^media[\\\/]gpu[\\\/].*\.cc$",
180 r"^gpu[\\\/].*\.cc$",
181 ),
182 ),
183 (
[email protected]23e6cbc2012-06-16 18:51:20184 'ScopedAllowIO',
185 (
[email protected]e3c945502012-06-26 20:01:49186 'New code should not use ScopedAllowIO. Post a task to the blocking',
187 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20188 ),
[email protected]e3c945502012-06-26 20:01:49189 True,
[email protected]7345da02012-11-27 14:31:49190 (
hajimehoshi2acea432017-03-08 08:55:37191 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
nyad2c548b2015-12-09 03:22:32192 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10193 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22194 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31195 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51196 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
197 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09198 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49199 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
200 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25201 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41202 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
203 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25204 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48205 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
206 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01207 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25208 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
209 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
210 r"embedded_test_server\.cc$",
211 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
212 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54213 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16214 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53215 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
216 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45217 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
218 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
219 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
220 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
221 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49222 ),
[email protected]23e6cbc2012-06-16 18:51:20223 ),
[email protected]52657f62013-05-20 05:30:31224 (
tomhudsone2c14d552016-05-26 17:07:46225 'setMatrixClip',
226 (
227 'Overriding setMatrixClip() is prohibited; ',
228 'the base function is deprecated. ',
229 ),
230 True,
231 (),
232 ),
233 (
[email protected]52657f62013-05-20 05:30:31234 'SkRefPtr',
235 (
236 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22237 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31238 ),
239 True,
240 (),
241 ),
242 (
243 'SkAutoRef',
244 (
245 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22246 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31247 ),
248 True,
249 (),
250 ),
251 (
252 'SkAutoTUnref',
253 (
254 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22255 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31256 ),
257 True,
258 (),
259 ),
260 (
261 'SkAutoUnref',
262 (
263 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
264 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22265 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31266 ),
267 True,
268 (),
269 ),
[email protected]d89eec82013-12-03 14:10:59270 (
271 r'/HANDLE_EINTR\(.*close',
272 (
273 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
274 'descriptor will be closed, and it is incorrect to retry the close.',
275 'Either call close directly and ignore its return value, or wrap close',
276 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
277 ),
278 True,
279 (),
280 ),
281 (
282 r'/IGNORE_EINTR\((?!.*close)',
283 (
284 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
285 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
286 ),
287 True,
288 (
289 # Files that #define IGNORE_EINTR.
290 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
291 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
292 ),
293 ),
[email protected]ec5b3f02014-04-04 18:43:43294 (
295 r'/v8::Extension\(',
296 (
297 'Do not introduce new v8::Extensions into the code base, use',
298 'gin::Wrappable instead. See http://crbug.com/334679',
299 ),
300 True,
[email protected]f55c90ee62014-04-12 00:50:03301 (
joaodasilva718f87672014-08-30 09:25:49302 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03303 ),
[email protected]ec5b3f02014-04-04 18:43:43304 ),
skyostilf9469f72015-04-20 10:38:52305 (
jame2d1a952016-04-02 00:27:10306 '#pragma comment(lib,',
307 (
308 'Specify libraries to link with in build files and not in the source.',
309 ),
310 True,
311 (),
312 ),
[email protected]127f18ec2012-06-16 05:05:59313)
314
wnwenbdc444e2016-05-25 13:44:15315
mlamouria82272622014-09-16 18:45:04316_IPC_ENUM_TRAITS_DEPRECATED = (
317 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
318 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
319
[email protected]127f18ec2012-06-16 05:05:59320
[email protected]b00342e7f2013-03-26 16:21:54321_VALID_OS_MACROS = (
322 # Please keep sorted.
323 'OS_ANDROID',
324 'OS_BSD',
325 'OS_CAT', # For testing.
326 'OS_CHROMEOS',
327 'OS_FREEBSD',
328 'OS_IOS',
329 'OS_LINUX',
330 'OS_MACOSX',
331 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21332 'OS_NACL_NONSFI',
333 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12334 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54335 'OS_OPENBSD',
336 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37337 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54338 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54339 'OS_WIN',
340)
341
342
agrievef32bcc72016-04-04 14:57:40343_ANDROID_SPECIFIC_PYDEPS_FILES = [
344 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04345 'build/android/test_wrapper/logdog_wrapper.pydeps',
agrieve732db3a2016-04-26 19:18:19346 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40347]
348
wnwenbdc444e2016-05-25 13:44:15349
agrievef32bcc72016-04-04 14:57:40350_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40351]
352
wnwenbdc444e2016-05-25 13:44:15353
agrievef32bcc72016-04-04 14:57:40354_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
355
356
[email protected]55459852011-08-10 15:17:19357def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
358 """Attempts to prevent use of functions intended only for testing in
359 non-testing code. For now this is just a best-effort implementation
360 that ignores header files and may have some false positives. A
361 better implementation would probably need a proper C++ parser.
362 """
363 # We only scan .cc files and the like, as the declaration of
364 # for-testing functions in header files are hard to distinguish from
365 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44366 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19367
jochenc0d4808c2015-07-27 09:25:42368 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19369 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09370 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19371 exclusion_pattern = input_api.re.compile(
372 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
373 base_function_pattern, base_function_pattern))
374
375 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44376 black_list = (_EXCLUDED_PATHS +
377 _TEST_CODE_EXCLUDED_PATHS +
378 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19379 return input_api.FilterSourceFile(
380 affected_file,
381 white_list=(file_inclusion_pattern, ),
382 black_list=black_list)
383
384 problems = []
385 for f in input_api.AffectedSourceFiles(FilterFile):
386 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24387 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03388 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46389 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03390 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19391 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03392 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19393
394 if problems:
[email protected]f7051d52013-04-02 18:31:42395 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03396 else:
397 return []
[email protected]55459852011-08-10 15:17:19398
399
[email protected]10689ca2011-09-02 02:31:54400def _CheckNoIOStreamInHeaders(input_api, output_api):
401 """Checks to make sure no .h files include <iostream>."""
402 files = []
403 pattern = input_api.re.compile(r'^#include\s*<iostream>',
404 input_api.re.MULTILINE)
405 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
406 if not f.LocalPath().endswith('.h'):
407 continue
408 contents = input_api.ReadFile(f)
409 if pattern.search(contents):
410 files.append(f)
411
412 if len(files):
yolandyandaabc6d2016-04-18 18:29:39413 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06414 'Do not #include <iostream> in header files, since it inserts static '
415 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54416 '#include <ostream>. See http://crbug.com/94794',
417 files) ]
418 return []
419
420
[email protected]72df4e782012-06-21 16:28:18421def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52422 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18423 problems = []
424 for f in input_api.AffectedFiles():
425 if (not f.LocalPath().endswith(('.cc', '.mm'))):
426 continue
427
428 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04429 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18430 problems.append(' %s:%d' % (f.LocalPath(), line_num))
431
432 if not problems:
433 return []
434 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
435 '\n'.join(problems))]
436
437
danakj61c1aa22015-10-26 19:55:52438def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57439 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52440 errors = []
441 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
442 input_api.re.MULTILINE)
443 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
444 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
445 continue
446 for lnum, line in f.ChangedContents():
447 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17448 errors.append(output_api.PresubmitError(
449 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57450 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17451 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52452 return errors
453
454
mcasasb7440c282015-02-04 14:52:19455def _FindHistogramNameInLine(histogram_name, line):
456 """Tries to find a histogram name or prefix in a line."""
457 if not "affected-histogram" in line:
458 return histogram_name in line
459 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
460 # the histogram_name.
461 if not '"' in line:
462 return False
463 histogram_prefix = line.split('\"')[1]
464 return histogram_prefix in histogram_name
465
466
467def _CheckUmaHistogramChanges(input_api, output_api):
468 """Check that UMA histogram names in touched lines can still be found in other
469 lines of the patch or in histograms.xml. Note that this check would not catch
470 the reverse: changes in histograms.xml not matched in the code itself."""
471 touched_histograms = []
472 histograms_xml_modifications = []
473 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
474 for f in input_api.AffectedFiles():
475 # If histograms.xml itself is modified, keep the modified lines for later.
476 if f.LocalPath().endswith(('histograms.xml')):
477 histograms_xml_modifications = f.ChangedContents()
478 continue
479 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
480 continue
481 for line_num, line in f.ChangedContents():
482 found = pattern.search(line)
483 if found:
484 touched_histograms.append([found.group(1), f, line_num])
485
486 # Search for the touched histogram names in the local modifications to
487 # histograms.xml, and, if not found, on the base histograms.xml file.
488 unmatched_histograms = []
489 for histogram_info in touched_histograms:
490 histogram_name_found = False
491 for line_num, line in histograms_xml_modifications:
492 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
493 if histogram_name_found:
494 break
495 if not histogram_name_found:
496 unmatched_histograms.append(histogram_info)
497
eromanb90c82e7e32015-04-01 15:13:49498 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19499 problems = []
500 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49501 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19502 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45503 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19504 histogram_name_found = False
505 for line in histograms_xml:
506 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
507 if histogram_name_found:
508 break
509 if not histogram_name_found:
510 problems.append(' [%s:%d] %s' %
511 (f.LocalPath(), line_num, histogram_name))
512
513 if not problems:
514 return []
515 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
516 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49517 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19518
wnwenbdc444e2016-05-25 13:44:15519
yolandyandaabc6d2016-04-18 18:29:39520def _CheckFlakyTestUsage(input_api, output_api):
521 """Check that FlakyTest annotation is our own instead of the android one"""
522 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
523 files = []
524 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
525 if f.LocalPath().endswith('Test.java'):
526 if pattern.search(input_api.ReadFile(f)):
527 files.append(f)
528 if len(files):
529 return [output_api.PresubmitError(
530 'Use org.chromium.base.test.util.FlakyTest instead of '
531 'android.test.FlakyTest',
532 files)]
533 return []
mcasasb7440c282015-02-04 14:52:19534
wnwenbdc444e2016-05-25 13:44:15535
[email protected]8ea5d4b2011-09-13 21:49:22536def _CheckNoNewWStrings(input_api, output_api):
537 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27538 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22539 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20540 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57541 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34542 '/win/' in f.LocalPath() or
543 'chrome_elf' in f.LocalPath() or
544 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20545 continue
[email protected]8ea5d4b2011-09-13 21:49:22546
[email protected]a11dbe9b2012-08-07 01:32:58547 allowWString = False
[email protected]b5c24292011-11-28 14:38:20548 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58549 if 'presubmit: allow wstring' in line:
550 allowWString = True
551 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27552 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58553 allowWString = False
554 else:
555 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22556
[email protected]55463aa62011-10-12 00:48:27557 if not problems:
558 return []
559 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58560 ' If you are calling a cross-platform API that accepts a wstring, '
561 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27562 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22563
564
[email protected]2a8ac9c2011-10-19 17:20:44565def _CheckNoDEPSGIT(input_api, output_api):
566 """Make sure .DEPS.git is never modified manually."""
567 if any(f.LocalPath().endswith('.DEPS.git') for f in
568 input_api.AffectedFiles()):
569 return [output_api.PresubmitError(
570 'Never commit changes to .DEPS.git. This file is maintained by an\n'
571 'automated system based on what\'s in DEPS and your changes will be\n'
572 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34573 '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:44574 'for more information')]
575 return []
576
577
tandriief664692014-09-23 14:51:47578def _CheckValidHostsInDEPS(input_api, output_api):
579 """Checks that DEPS file deps are from allowed_hosts."""
580 # Run only if DEPS file has been modified to annoy fewer bystanders.
581 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
582 return []
583 # Outsource work to gclient verify
584 try:
585 input_api.subprocess.check_output(['gclient', 'verify'])
586 return []
587 except input_api.subprocess.CalledProcessError, error:
588 return [output_api.PresubmitError(
589 'DEPS file must have only git dependencies.',
590 long_text=error.output)]
591
592
[email protected]127f18ec2012-06-16 05:05:59593def _CheckNoBannedFunctions(input_api, output_api):
594 """Make sure that banned functions are not used."""
595 warnings = []
596 errors = []
597
wnwenbdc444e2016-05-25 13:44:15598 def IsBlacklisted(affected_file, blacklist):
599 local_path = affected_file.LocalPath()
600 for item in blacklist:
601 if input_api.re.match(item, local_path):
602 return True
603 return False
604
605 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
606 matched = False
607 if func_name[0:1] == '/':
608 regex = func_name[1:]
609 if input_api.re.search(regex, line):
610 matched = True
611 elif func_name in line:
dchenge07de812016-06-20 19:27:17612 matched = True
wnwenbdc444e2016-05-25 13:44:15613 if matched:
dchenge07de812016-06-20 19:27:17614 problems = warnings
wnwenbdc444e2016-05-25 13:44:15615 if error:
dchenge07de812016-06-20 19:27:17616 problems = errors
wnwenbdc444e2016-05-25 13:44:15617 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
618 for message_line in message:
619 problems.append(' %s' % message_line)
620
[email protected]127f18ec2012-06-16 05:05:59621 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
622 for f in input_api.AffectedFiles(file_filter=file_filter):
623 for line_num, line in f.ChangedContents():
624 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15625 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59626
627 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
628 for f in input_api.AffectedFiles(file_filter=file_filter):
629 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49630 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49631 if IsBlacklisted(f, excluded_paths):
632 continue
wnwenbdc444e2016-05-25 13:44:15633 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59634
635 result = []
636 if (warnings):
637 result.append(output_api.PresubmitPromptWarning(
638 'Banned functions were used.\n' + '\n'.join(warnings)))
639 if (errors):
640 result.append(output_api.PresubmitError(
641 'Banned functions were used.\n' + '\n'.join(errors)))
642 return result
643
644
[email protected]6c063c62012-07-11 19:11:06645def _CheckNoPragmaOnce(input_api, output_api):
646 """Make sure that banned functions are not used."""
647 files = []
648 pattern = input_api.re.compile(r'^#pragma\s+once',
649 input_api.re.MULTILINE)
650 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
651 if not f.LocalPath().endswith('.h'):
652 continue
653 contents = input_api.ReadFile(f)
654 if pattern.search(contents):
655 files.append(f)
656
657 if files:
658 return [output_api.PresubmitError(
659 'Do not use #pragma once in header files.\n'
660 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
661 files)]
662 return []
663
[email protected]127f18ec2012-06-16 05:05:59664
[email protected]e7479052012-09-19 00:26:12665def _CheckNoTrinaryTrueFalse(input_api, output_api):
666 """Checks to make sure we don't introduce use of foo ? true : false."""
667 problems = []
668 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
669 for f in input_api.AffectedFiles():
670 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
671 continue
672
673 for line_num, line in f.ChangedContents():
674 if pattern.match(line):
675 problems.append(' %s:%d' % (f.LocalPath(), line_num))
676
677 if not problems:
678 return []
679 return [output_api.PresubmitPromptWarning(
680 'Please consider avoiding the "? true : false" pattern if possible.\n' +
681 '\n'.join(problems))]
682
683
[email protected]55f9f382012-07-31 11:02:18684def _CheckUnwantedDependencies(input_api, output_api):
685 """Runs checkdeps on #include statements added in this
686 change. Breaking - rules is an error, breaking ! rules is a
687 warning.
688 """
mohan.reddyf21db962014-10-16 12:26:47689 import sys
[email protected]55f9f382012-07-31 11:02:18690 # We need to wait until we have an input_api object and use this
691 # roundabout construct to import checkdeps because this file is
692 # eval-ed and thus doesn't have __file__.
693 original_sys_path = sys.path
694 try:
695 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47696 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18697 import checkdeps
698 from cpp_checker import CppChecker
699 from rules import Rule
700 finally:
701 # Restore sys.path to what it was before.
702 sys.path = original_sys_path
703
704 added_includes = []
705 for f in input_api.AffectedFiles():
706 if not CppChecker.IsCppFile(f.LocalPath()):
707 continue
708
709 changed_lines = [line for line_num, line in f.ChangedContents()]
710 added_includes.append([f.LocalPath(), changed_lines])
711
[email protected]26385172013-05-09 23:11:35712 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18713
714 error_descriptions = []
715 warning_descriptions = []
716 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
717 added_includes):
718 description_with_path = '%s\n %s' % (path, rule_description)
719 if rule_type == Rule.DISALLOW:
720 error_descriptions.append(description_with_path)
721 else:
722 warning_descriptions.append(description_with_path)
723
724 results = []
725 if error_descriptions:
726 results.append(output_api.PresubmitError(
727 'You added one or more #includes that violate checkdeps rules.',
728 error_descriptions))
729 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42730 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18731 'You added one or more #includes of files that are temporarily\n'
732 'allowed but being removed. Can you avoid introducing the\n'
733 '#include? See relevant DEPS file(s) for details and contacts.',
734 warning_descriptions))
735 return results
736
737
[email protected]fbcafe5a2012-08-08 15:31:22738def _CheckFilePermissions(input_api, output_api):
739 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15740 if input_api.platform == 'win32':
741 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29742 checkperms_tool = input_api.os_path.join(
743 input_api.PresubmitLocalPath(),
744 'tools', 'checkperms', 'checkperms.py')
745 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47746 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22747 for f in input_api.AffectedFiles():
748 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11749 try:
750 input_api.subprocess.check_output(args)
751 return []
752 except input_api.subprocess.CalledProcessError as error:
753 return [output_api.PresubmitError(
754 'checkperms.py failed:',
755 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22756
757
robertocn832f5992017-01-04 19:01:30758def _CheckTeamTags(input_api, output_api):
759 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
760 checkteamtags_tool = input_api.os_path.join(
761 input_api.PresubmitLocalPath(),
762 'tools', 'checkteamtags', 'checkteamtags.py')
763 args = [input_api.python_executable, checkteamtags_tool,
764 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22765 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30766 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
767 'OWNERS']
768 try:
769 if files:
770 input_api.subprocess.check_output(args + files)
771 return []
772 except input_api.subprocess.CalledProcessError as error:
773 return [output_api.PresubmitError(
774 'checkteamtags.py failed:',
775 long_text=error.output)]
776
777
[email protected]c8278b32012-10-30 20:35:49778def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
779 """Makes sure we don't include ui/aura/window_property.h
780 in header files.
781 """
782 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
783 errors = []
784 for f in input_api.AffectedFiles():
785 if not f.LocalPath().endswith('.h'):
786 continue
787 for line_num, line in f.ChangedContents():
788 if pattern.match(line):
789 errors.append(' %s:%d' % (f.LocalPath(), line_num))
790
791 results = []
792 if errors:
793 results.append(output_api.PresubmitError(
794 'Header files should not include ui/aura/window_property.h', errors))
795 return results
796
797
[email protected]cf9b78f2012-11-14 11:40:28798def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
799 """Checks that the lines in scope occur in the right order.
800
801 1. C system files in alphabetical order
802 2. C++ system files in alphabetical order
803 3. Project's .h files
804 """
805
806 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
807 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
808 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
809
810 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
811
812 state = C_SYSTEM_INCLUDES
813
814 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57815 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28816 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55817 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28818 for line_num, line in scope:
819 if c_system_include_pattern.match(line):
820 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55821 problem_linenums.append((line_num, previous_line_num,
822 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28823 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55824 problem_linenums.append((line_num, previous_line_num,
825 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28826 elif cpp_system_include_pattern.match(line):
827 if state == C_SYSTEM_INCLUDES:
828 state = CPP_SYSTEM_INCLUDES
829 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55830 problem_linenums.append((line_num, previous_line_num,
831 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28832 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 elif custom_include_pattern.match(line):
835 if state != CUSTOM_INCLUDES:
836 state = CUSTOM_INCLUDES
837 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55838 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28839 else:
brucedawson70fadb02015-06-30 17:47:55840 problem_linenums.append((line_num, previous_line_num,
841 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28842 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57843 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28844
845 warnings = []
brucedawson70fadb02015-06-30 17:47:55846 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57847 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55848 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28849 return warnings
850
851
[email protected]ac294a12012-12-06 16:38:43852def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28853 """Checks the #include order for the given file f."""
854
[email protected]2299dcf2012-11-15 19:56:24855 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30856 # Exclude the following includes from the check:
857 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
858 # specific order.
859 # 2) <atlbase.h>, "build/build_config.h"
860 excluded_include_pattern = input_api.re.compile(
861 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24862 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33863 # Match the final or penultimate token if it is xxxtest so we can ignore it
864 # when considering the special first include.
865 test_file_tag_pattern = input_api.re.compile(
866 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11867 if_pattern = input_api.re.compile(
868 r'\s*#\s*(if|elif|else|endif|define|undef).*')
869 # Some files need specialized order of includes; exclude such files from this
870 # check.
871 uncheckable_includes_pattern = input_api.re.compile(
872 r'\s*#include '
873 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28874
875 contents = f.NewContents()
876 warnings = []
877 line_num = 0
878
[email protected]ac294a12012-12-06 16:38:43879 # Handle the special first include. If the first include file is
880 # some/path/file.h, the corresponding including file can be some/path/file.cc,
881 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
882 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33883 # If the included file is some/path/file_platform.h the including file could
884 # also be some/path/file_xxxtest_platform.h.
885 including_file_base_name = test_file_tag_pattern.sub(
886 '', input_api.os_path.basename(f.LocalPath()))
887
[email protected]ac294a12012-12-06 16:38:43888 for line in contents:
889 line_num += 1
890 if system_include_pattern.match(line):
891 # No special first include -> process the line again along with normal
892 # includes.
893 line_num -= 1
894 break
895 match = custom_include_pattern.match(line)
896 if match:
897 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33898 header_basename = test_file_tag_pattern.sub(
899 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
900
901 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24902 # No special first include -> process the line again along with normal
903 # includes.
904 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43905 break
[email protected]cf9b78f2012-11-14 11:40:28906
907 # Split into scopes: Each region between #if and #endif is its own scope.
908 scopes = []
909 current_scope = []
910 for line in contents[line_num:]:
911 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11912 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54913 continue
[email protected]2309b0fa02012-11-16 12:18:27914 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28915 scopes.append(current_scope)
916 current_scope = []
[email protected]962f117e2012-11-22 18:11:56917 elif ((system_include_pattern.match(line) or
918 custom_include_pattern.match(line)) and
919 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28920 current_scope.append((line_num, line))
921 scopes.append(current_scope)
922
923 for scope in scopes:
924 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
925 changed_linenums))
926 return warnings
927
928
929def _CheckIncludeOrder(input_api, output_api):
930 """Checks that the #include order is correct.
931
932 1. The corresponding header for source files.
933 2. C system files in alphabetical order
934 3. C++ system files in alphabetical order
935 4. Project's .h files in alphabetical order
936
[email protected]ac294a12012-12-06 16:38:43937 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
938 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28939 """
[email protected]e120b012014-08-15 19:08:35940 def FileFilterIncludeOrder(affected_file):
941 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
942 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28943
944 warnings = []
[email protected]e120b012014-08-15 19:08:35945 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08946 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43947 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
948 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28949
950 results = []
951 if warnings:
[email protected]f7051d52013-04-02 18:31:42952 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53953 warnings))
[email protected]cf9b78f2012-11-14 11:40:28954 return results
955
956
[email protected]70ca77752012-11-20 03:45:03957def _CheckForVersionControlConflictsInFile(input_api, f):
958 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
959 errors = []
960 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23961 if f.LocalPath().endswith('.md'):
962 # First-level headers in markdown look a lot like version control
963 # conflict markers. http://daringfireball.net/projects/markdown/basics
964 continue
[email protected]70ca77752012-11-20 03:45:03965 if pattern.match(line):
966 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
967 return errors
968
969
970def _CheckForVersionControlConflicts(input_api, output_api):
971 """Usually this is not intentional and will cause a compile failure."""
972 errors = []
973 for f in input_api.AffectedFiles():
974 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
975
976 results = []
977 if errors:
978 results.append(output_api.PresubmitError(
979 'Version control conflict markers found, please resolve.', errors))
980 return results
981
estadee17314a02017-01-12 16:22:16982def _CheckGoogleSupportAnswerUrl(input_api, output_api):
983 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
984 errors = []
985 for f in input_api.AffectedFiles():
986 for line_num, line in f.ChangedContents():
987 if pattern.search(line):
988 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
989
990 results = []
991 if errors:
992 results.append(output_api.PresubmitPromptWarning(
993 'Found Google support URL addressed by answer number. Please replace with '
994 'a p= identifier instead. See crbug.com/679462\n', errors))
995 return results
996
[email protected]70ca77752012-11-20 03:45:03997
[email protected]06e6d0ff2012-12-11 01:36:44998def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
999 def FilterFile(affected_file):
1000 """Filter function for use with input_api.AffectedSourceFiles,
1001 below. This filters out everything except non-test files from
1002 top-level directories that generally speaking should not hard-code
1003 service URLs (e.g. src/android_webview/, src/content/ and others).
1004 """
1005 return input_api.FilterSourceFile(
1006 affected_file,
[email protected]78bb39d62012-12-11 15:11:561007 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441008 black_list=(_EXCLUDED_PATHS +
1009 _TEST_CODE_EXCLUDED_PATHS +
1010 input_api.DEFAULT_BLACK_LIST))
1011
reillyi38965732015-11-16 18:27:331012 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1013 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461014 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1015 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441016 problems = [] # items are (filename, line_number, line)
1017 for f in input_api.AffectedSourceFiles(FilterFile):
1018 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461019 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441020 problems.append((f.LocalPath(), line_num, line))
1021
1022 if problems:
[email protected]f7051d52013-04-02 18:31:421023 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441024 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581025 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441026 [' %s:%d: %s' % (
1027 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031028 else:
1029 return []
[email protected]06e6d0ff2012-12-11 01:36:441030
1031
[email protected]d2530012013-01-25 16:39:271032def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1033 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311034 The native_client_sdk directory is excluded because it has auto-generated PNG
1035 files for documentation.
[email protected]d2530012013-01-25 16:39:271036 """
[email protected]d2530012013-01-25 16:39:271037 errors = []
binji0dcdf342014-12-12 18:32:311038 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1039 black_list = (r'^native_client_sdk[\\\/]',)
1040 file_filter = lambda f: input_api.FilterSourceFile(
1041 f, white_list=white_list, black_list=black_list)
1042 for f in input_api.AffectedFiles(include_deletes=False,
1043 file_filter=file_filter):
1044 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271045
1046 results = []
1047 if errors:
1048 results.append(output_api.PresubmitError(
1049 'The name of PNG files should not have abbreviations. \n'
1050 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1051 'Contact [email protected] if you have questions.', errors))
1052 return results
1053
1054
ksakamotob89c4322017-03-23 04:39:101055def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:081056 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411057 a set of DEPS entries that we should look up.
1058
1059 For a directory (rather than a specific filename) we fake a path to
1060 a specific filename by adding /DEPS. This is chosen as a file that
1061 will seldom or never be subject to per-file include_rules.
1062 """
[email protected]2b438d62013-11-14 17:54:141063 # We ignore deps entries on auto-generated directories.
1064 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081065
ksakamotob89c4322017-03-23 04:39:101066 # This pattern grabs the path without basename in the first
1067 # parentheses, and the basename (if present) in the second. It
1068 # relies on the simple heuristic that if there is a basename it will
1069 # be a header file ending in ".h".
1070 pattern = re.compile(
1071 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141072 results = set()
ksakamotob89c4322017-03-23 04:39:101073 for changed_line in changed_lines:
1074 m = pattern.match(changed_line)
1075 if m:
1076 path = m.group(1)
1077 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
1078 if m.group(2):
1079 results.add('%s%s' % (path, m.group(2)))
1080 else:
1081 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081082 return results
1083
1084
[email protected]e871964c2013-05-13 14:14:551085def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1086 """When a dependency prefixed with + is added to a DEPS file, we
1087 want to make sure that the change is reviewed by an OWNER of the
1088 target file or directory, to avoid layering violations from being
1089 introduced. This check verifies that this happens.
1090 """
ksakamotob89c4322017-03-23 04:39:101091 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241092
1093 file_filter = lambda f: not input_api.re.match(
1094 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1095 for f in input_api.AffectedFiles(include_deletes=False,
1096 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551097 filename = input_api.os_path.basename(f.LocalPath())
1098 if filename == 'DEPS':
ksakamotob89c4322017-03-23 04:39:101099 changed_lines |= set(line.strip()
1100 for line_num, line
1101 in f.ChangedContents())
1102 if not changed_lines:
1103 return []
[email protected]e871964c2013-05-13 14:14:551104
ksakamotob89c4322017-03-23 04:39:101105 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1106 changed_lines)
[email protected]e871964c2013-05-13 14:14:551107 if not virtual_depended_on_files:
1108 return []
1109
1110 if input_api.is_committing:
1111 if input_api.tbr:
1112 return [output_api.PresubmitNotifyResult(
1113 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271114 if input_api.dry_run:
1115 return [output_api.PresubmitNotifyResult(
1116 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551117 if not input_api.change.issue:
1118 return [output_api.PresubmitError(
1119 "DEPS approval by OWNERS check failed: this change has "
1120 "no Rietveld issue number, so we can't check it for approvals.")]
1121 output = output_api.PresubmitError
1122 else:
1123 output = output_api.PresubmitNotifyResult
1124
1125 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501126 owner_email, reviewers = (
1127 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1128 input_api,
1129 owners_db.email_regexp,
1130 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551131
1132 owner_email = owner_email or input_api.change.author_email
1133
[email protected]de4f7d22013-05-23 14:27:461134 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511135 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461136 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551137 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1138 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411139
1140 # We strip the /DEPS part that was added by
1141 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1142 # directory.
1143 def StripDeps(path):
1144 start_deps = path.rfind('/DEPS')
1145 if start_deps != -1:
1146 return path[:start_deps]
1147 else:
1148 return path
1149 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551150 for path in missing_files]
1151
1152 if unapproved_dependencies:
1153 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151154 output('You need LGTM from owners of depends-on paths in DEPS that were '
1155 'modified in this CL:\n %s' %
1156 '\n '.join(sorted(unapproved_dependencies)))]
1157 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1158 output_list.append(output(
1159 'Suggested missing target path OWNERS:\n %s' %
1160 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551161 return output_list
1162
1163 return []
1164
1165
[email protected]85218562013-11-22 07:41:401166def _CheckSpamLogging(input_api, output_api):
1167 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1168 black_list = (_EXCLUDED_PATHS +
1169 _TEST_CODE_EXCLUDED_PATHS +
1170 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501171 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191172 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481173 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461174 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121175 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1176 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581177 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161178 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031179 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151180 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1181 r"^chromecast[\\\/]",
1182 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311183 r"^components[\\\/]html_viewer[\\\/]"
1184 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461185 # TODO(peter): Remove this exception. https://crbug.com/534537
1186 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1187 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251188 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1189 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241190 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111191 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151192 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111193 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521194 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501195 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361196 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311197 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131198 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001199 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441200 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451201 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021202 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351203 r"dump_file_system.cc$",
1204 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401205 source_file_filter = lambda x: input_api.FilterSourceFile(
1206 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1207
1208 log_info = []
1209 printf = []
1210
1211 for f in input_api.AffectedSourceFiles(source_file_filter):
1212 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471213 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401214 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471215 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131216 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371217
mohan.reddyf21db962014-10-16 12:26:471218 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371219 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471220 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401221 printf.append(f.LocalPath())
1222
1223 if log_info:
1224 return [output_api.PresubmitError(
1225 'These files spam the console log with LOG(INFO):',
1226 items=log_info)]
1227 if printf:
1228 return [output_api.PresubmitError(
1229 'These files spam the console log with printf/fprintf:',
1230 items=printf)]
1231 return []
1232
1233
[email protected]49aa76a2013-12-04 06:59:161234def _CheckForAnonymousVariables(input_api, output_api):
1235 """These types are all expected to hold locks while in scope and
1236 so should never be anonymous (which causes them to be immediately
1237 destroyed)."""
1238 they_who_must_be_named = [
1239 'base::AutoLock',
1240 'base::AutoReset',
1241 'base::AutoUnlock',
1242 'SkAutoAlphaRestore',
1243 'SkAutoBitmapShaderInstall',
1244 'SkAutoBlitterChoose',
1245 'SkAutoBounderCommit',
1246 'SkAutoCallProc',
1247 'SkAutoCanvasRestore',
1248 'SkAutoCommentBlock',
1249 'SkAutoDescriptor',
1250 'SkAutoDisableDirectionCheck',
1251 'SkAutoDisableOvalCheck',
1252 'SkAutoFree',
1253 'SkAutoGlyphCache',
1254 'SkAutoHDC',
1255 'SkAutoLockColors',
1256 'SkAutoLockPixels',
1257 'SkAutoMalloc',
1258 'SkAutoMaskFreeImage',
1259 'SkAutoMutexAcquire',
1260 'SkAutoPathBoundsUpdate',
1261 'SkAutoPDFRelease',
1262 'SkAutoRasterClipValidate',
1263 'SkAutoRef',
1264 'SkAutoTime',
1265 'SkAutoTrace',
1266 'SkAutoUnref',
1267 ]
1268 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1269 # bad: base::AutoLock(lock.get());
1270 # not bad: base::AutoLock lock(lock.get());
1271 bad_pattern = input_api.re.compile(anonymous)
1272 # good: new base::AutoLock(lock.get())
1273 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1274 errors = []
1275
1276 for f in input_api.AffectedFiles():
1277 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1278 continue
1279 for linenum, line in f.ChangedContents():
1280 if bad_pattern.search(line) and not good_pattern.search(line):
1281 errors.append('%s:%d' % (f.LocalPath(), linenum))
1282
1283 if errors:
1284 return [output_api.PresubmitError(
1285 'These lines create anonymous variables that need to be named:',
1286 items=errors)]
1287 return []
1288
1289
[email protected]5fe0f8742013-11-29 01:04:591290def _CheckCygwinShell(input_api, output_api):
1291 source_file_filter = lambda x: input_api.FilterSourceFile(
1292 x, white_list=(r'.+\.(gyp|gypi)$',))
1293 cygwin_shell = []
1294
1295 for f in input_api.AffectedSourceFiles(source_file_filter):
1296 for linenum, line in f.ChangedContents():
1297 if 'msvs_cygwin_shell' in line:
1298 cygwin_shell.append(f.LocalPath())
1299 break
1300
1301 if cygwin_shell:
1302 return [output_api.PresubmitError(
1303 'These files should not use msvs_cygwin_shell (the default is 0):',
1304 items=cygwin_shell)]
1305 return []
1306
[email protected]85218562013-11-22 07:41:401307
[email protected]999261d2014-03-03 20:08:081308def _CheckUserActionUpdate(input_api, output_api):
1309 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521310 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081311 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521312 # If actions.xml is already included in the changelist, the PRESUBMIT
1313 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081314 return []
1315
[email protected]999261d2014-03-03 20:08:081316 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1317 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521318 current_actions = None
[email protected]999261d2014-03-03 20:08:081319 for f in input_api.AffectedFiles(file_filter=file_filter):
1320 for line_num, line in f.ChangedContents():
1321 match = input_api.re.search(action_re, line)
1322 if match:
[email protected]2f92dec2014-03-07 19:21:521323 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1324 # loaded only once.
1325 if not current_actions:
1326 with open('tools/metrics/actions/actions.xml') as actions_f:
1327 current_actions = actions_f.read()
1328 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081329 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521330 action = 'name="{0}"'.format(action_name)
1331 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081332 return [output_api.PresubmitPromptWarning(
1333 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521334 'tools/metrics/actions/actions.xml. Please run '
1335 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081336 % (f.LocalPath(), line_num, action_name))]
1337 return []
1338
1339
[email protected]99171a92014-06-03 08:44:471340def _GetJSONParseError(input_api, filename, eat_comments=True):
1341 try:
1342 contents = input_api.ReadFile(filename)
1343 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131344 import sys
1345 original_sys_path = sys.path
1346 try:
1347 sys.path = sys.path + [input_api.os_path.join(
1348 input_api.PresubmitLocalPath(),
1349 'tools', 'json_comment_eater')]
1350 import json_comment_eater
1351 finally:
1352 sys.path = original_sys_path
1353 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471354
1355 input_api.json.loads(contents)
1356 except ValueError as e:
1357 return e
1358 return None
1359
1360
1361def _GetIDLParseError(input_api, filename):
1362 try:
1363 contents = input_api.ReadFile(filename)
1364 idl_schema = input_api.os_path.join(
1365 input_api.PresubmitLocalPath(),
1366 'tools', 'json_schema_compiler', 'idl_schema.py')
1367 process = input_api.subprocess.Popen(
1368 [input_api.python_executable, idl_schema],
1369 stdin=input_api.subprocess.PIPE,
1370 stdout=input_api.subprocess.PIPE,
1371 stderr=input_api.subprocess.PIPE,
1372 universal_newlines=True)
1373 (_, error) = process.communicate(input=contents)
1374 return error or None
1375 except ValueError as e:
1376 return e
1377
1378
1379def _CheckParseErrors(input_api, output_api):
1380 """Check that IDL and JSON files do not contain syntax errors."""
1381 actions = {
1382 '.idl': _GetIDLParseError,
1383 '.json': _GetJSONParseError,
1384 }
1385 # These paths contain test data and other known invalid JSON files.
1386 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491387 r'test[\\\/]data[\\\/]',
1388 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471389 ]
1390 # Most JSON files are preprocessed and support comments, but these do not.
1391 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491392 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471393 ]
1394 # Only run IDL checker on files in these directories.
1395 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491396 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1397 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471398 ]
1399
1400 def get_action(affected_file):
1401 filename = affected_file.LocalPath()
1402 return actions.get(input_api.os_path.splitext(filename)[1])
1403
1404 def MatchesFile(patterns, path):
1405 for pattern in patterns:
1406 if input_api.re.search(pattern, path):
1407 return True
1408 return False
1409
1410 def FilterFile(affected_file):
1411 action = get_action(affected_file)
1412 if not action:
1413 return False
1414 path = affected_file.LocalPath()
1415
1416 if MatchesFile(excluded_patterns, path):
1417 return False
1418
1419 if (action == _GetIDLParseError and
1420 not MatchesFile(idl_included_patterns, path)):
1421 return False
1422 return True
1423
1424 results = []
1425 for affected_file in input_api.AffectedFiles(
1426 file_filter=FilterFile, include_deletes=False):
1427 action = get_action(affected_file)
1428 kwargs = {}
1429 if (action == _GetJSONParseError and
1430 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1431 kwargs['eat_comments'] = False
1432 parse_error = action(input_api,
1433 affected_file.AbsoluteLocalPath(),
1434 **kwargs)
1435 if parse_error:
1436 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1437 (affected_file.LocalPath(), parse_error)))
1438 return results
1439
1440
[email protected]760deea2013-12-10 19:33:491441def _CheckJavaStyle(input_api, output_api):
1442 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471443 import sys
[email protected]760deea2013-12-10 19:33:491444 original_sys_path = sys.path
1445 try:
1446 sys.path = sys.path + [input_api.os_path.join(
1447 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1448 import checkstyle
1449 finally:
1450 # Restore sys.path to what it was before.
1451 sys.path = original_sys_path
1452
1453 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091454 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511455 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491456
1457
dchenge07de812016-06-20 19:27:171458def _CheckIpcOwners(input_api, output_api):
1459 """Checks that affected files involving IPC have an IPC OWNERS rule.
1460
1461 Whether or not a file affects IPC is determined by a simple whitelist of
1462 filename patterns."""
1463 file_patterns = [
palmerb19a0932017-01-24 04:00:311464 # Legacy IPC:
dchenge07de812016-06-20 19:27:171465 '*_messages.cc',
1466 '*_messages*.h',
1467 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311468 # Mojo IPC:
dchenge07de812016-06-20 19:27:171469 '*.mojom',
1470 '*_struct_traits*.*',
1471 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311472 '*.typemap',
1473 # Android native IPC:
1474 '*.aidl',
1475 # Blink uses a different file naming convention:
1476 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171477 '*StructTraits*.*',
1478 '*TypeConverter*.*',
1479 ]
1480
scottmg7a6ed5ba2016-11-04 18:22:041481 # These third_party directories do not contain IPCs, but contain files
1482 # matching the above patterns, which trigger false positives.
1483 exclude_paths = [
1484 'third_party/crashpad/*',
1485 ]
1486
dchenge07de812016-06-20 19:27:171487 # Dictionary mapping an OWNERS file path to Patterns.
1488 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1489 # rules ) to a PatternEntry.
1490 # PatternEntry is a dictionary with two keys:
1491 # - 'files': the files that are matched by this pattern
1492 # - 'rules': the per-file rules needed for this pattern
1493 # For example, if we expect OWNERS file to contain rules for *.mojom and
1494 # *_struct_traits*.*, Patterns might look like this:
1495 # {
1496 # '*.mojom': {
1497 # 'files': ...,
1498 # 'rules': [
1499 # 'per-file *.mojom=set noparent',
1500 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1501 # ],
1502 # },
1503 # '*_struct_traits*.*': {
1504 # 'files': ...,
1505 # 'rules': [
1506 # 'per-file *_struct_traits*.*=set noparent',
1507 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1508 # ],
1509 # },
1510 # }
1511 to_check = {}
1512
1513 # Iterate through the affected files to see what we actually need to check
1514 # for. We should only nag patch authors about per-file rules if a file in that
1515 # directory would match that pattern. If a directory only contains *.mojom
1516 # files and no *_messages*.h files, we should only nag about rules for
1517 # *.mojom files.
rockot51249332016-06-23 16:32:251518 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171519 for pattern in file_patterns:
1520 if input_api.fnmatch.fnmatch(
1521 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041522 skip = False
1523 for exclude in exclude_paths:
1524 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1525 skip = True
1526 break
1527 if skip:
1528 continue
dchenge07de812016-06-20 19:27:171529 owners_file = input_api.os_path.join(
1530 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1531 if owners_file not in to_check:
1532 to_check[owners_file] = {}
1533 if pattern not in to_check[owners_file]:
1534 to_check[owners_file][pattern] = {
1535 'files': [],
1536 'rules': [
1537 'per-file %s=set noparent' % pattern,
1538 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1539 ]
1540 }
1541 to_check[owners_file][pattern]['files'].append(f)
1542 break
1543
1544 # Now go through the OWNERS files we collected, filtering out rules that are
1545 # already present in that OWNERS file.
1546 for owners_file, patterns in to_check.iteritems():
1547 try:
1548 with file(owners_file) as f:
1549 lines = set(f.read().splitlines())
1550 for entry in patterns.itervalues():
1551 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1552 ]
1553 except IOError:
1554 # No OWNERS file, so all the rules are definitely missing.
1555 continue
1556
1557 # All the remaining lines weren't found in OWNERS files, so emit an error.
1558 errors = []
1559 for owners_file, patterns in to_check.iteritems():
1560 missing_lines = []
1561 files = []
1562 for pattern, entry in patterns.iteritems():
1563 missing_lines.extend(entry['rules'])
1564 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1565 if missing_lines:
1566 errors.append(
1567 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1568 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1569
1570 results = []
1571 if errors:
vabrf5ce3bf92016-07-11 14:52:411572 if input_api.is_committing:
1573 output = output_api.PresubmitError
1574 else:
1575 output = output_api.PresubmitPromptWarning
1576 results.append(output(
dchenge07de812016-06-20 19:27:171577 'Found changes to IPC files without a security OWNER!',
1578 long_text='\n\n'.join(errors)))
1579
1580 return results
1581
1582
jbriance9e12f162016-11-25 07:57:501583def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311584 """Checks that added or removed lines in non third party affected
1585 header files do not lead to new useless class or struct forward
1586 declaration.
jbriance9e12f162016-11-25 07:57:501587 """
1588 results = []
1589 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1590 input_api.re.MULTILINE)
1591 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1592 input_api.re.MULTILINE)
1593 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311594 if (f.LocalPath().startswith('third_party') and
1595 not f.LocalPath().startswith('third_party/WebKit') and
1596 not f.LocalPath().startswith('third_party\\WebKit')):
1597 continue
1598
jbriance9e12f162016-11-25 07:57:501599 if not f.LocalPath().endswith('.h'):
1600 continue
1601
1602 contents = input_api.ReadFile(f)
1603 fwd_decls = input_api.re.findall(class_pattern, contents)
1604 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1605
1606 useless_fwd_decls = []
1607 for decl in fwd_decls:
1608 count = sum(1 for _ in input_api.re.finditer(
1609 r'\b%s\b' % input_api.re.escape(decl), contents))
1610 if count == 1:
1611 useless_fwd_decls.append(decl)
1612
1613 if not useless_fwd_decls:
1614 continue
1615
1616 for line in f.GenerateScmDiff().splitlines():
1617 if (line.startswith('-') and not line.startswith('--') or
1618 line.startswith('+') and not line.startswith('++')):
1619 for decl in useless_fwd_decls:
1620 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1621 results.append(output_api.PresubmitPromptWarning(
1622 '%s: %s forward declaration is becoming useless' %
1623 (f.LocalPath(), decl)))
1624 useless_fwd_decls.remove(decl)
1625
1626 return results
1627
1628
dskiba88634f4e2015-08-14 23:03:291629def _CheckAndroidToastUsage(input_api, output_api):
1630 """Checks that code uses org.chromium.ui.widget.Toast instead of
1631 android.widget.Toast (Chromium Toast doesn't force hardware
1632 acceleration on low-end devices, saving memory).
1633 """
1634 toast_import_pattern = input_api.re.compile(
1635 r'^import android\.widget\.Toast;$')
1636
1637 errors = []
1638
1639 sources = lambda affected_file: input_api.FilterSourceFile(
1640 affected_file,
1641 black_list=(_EXCLUDED_PATHS +
1642 _TEST_CODE_EXCLUDED_PATHS +
1643 input_api.DEFAULT_BLACK_LIST +
1644 (r'^chromecast[\\\/].*',
1645 r'^remoting[\\\/].*')),
1646 white_list=(r'.*\.java$',))
1647
1648 for f in input_api.AffectedSourceFiles(sources):
1649 for line_num, line in f.ChangedContents():
1650 if toast_import_pattern.search(line):
1651 errors.append("%s:%d" % (f.LocalPath(), line_num))
1652
1653 results = []
1654
1655 if errors:
1656 results.append(output_api.PresubmitError(
1657 'android.widget.Toast usage is detected. Android toasts use hardware'
1658 ' acceleration, and can be\ncostly on low-end devices. Please use'
1659 ' org.chromium.ui.widget.Toast instead.\n'
1660 'Contact [email protected] if you have any questions.',
1661 errors))
1662
1663 return results
1664
1665
dgnaa68d5e2015-06-10 10:08:221666def _CheckAndroidCrLogUsage(input_api, output_api):
1667 """Checks that new logs using org.chromium.base.Log:
1668 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511669 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221670 """
pkotwicza1dd0b002016-05-16 14:41:041671
torne89540622017-03-24 19:41:301672 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041673 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301674 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041675 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301676 # WebView license viewer code cannot depend on //base; used in stub APK.
1677 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1678 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041679 ]
1680
dgnaa68d5e2015-06-10 10:08:221681 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121682 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1683 class_in_base_pattern = input_api.re.compile(
1684 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1685 has_some_log_import_pattern = input_api.re.compile(
1686 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221687 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121688 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221689 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511690 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221691 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221692
Vincent Scheib16d7b272015-09-15 18:09:071693 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221694 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041695 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1696 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121697
dgnaa68d5e2015-06-10 10:08:221698 tag_decl_errors = []
1699 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121700 tag_errors = []
dgn38736db2015-09-18 19:20:511701 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121702 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221703
1704 for f in input_api.AffectedSourceFiles(sources):
1705 file_content = input_api.ReadFile(f)
1706 has_modified_logs = False
1707
1708 # Per line checks
dgn87d9fb62015-06-12 09:15:121709 if (cr_log_import_pattern.search(file_content) or
1710 (class_in_base_pattern.search(file_content) and
1711 not has_some_log_import_pattern.search(file_content))):
1712 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221713 for line_num, line in f.ChangedContents():
1714
1715 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121716 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221717 if match:
1718 has_modified_logs = True
1719
1720 # Make sure it uses "TAG"
1721 if not match.group('tag') == 'TAG':
1722 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121723 else:
1724 # Report non cr Log function calls in changed lines
1725 for line_num, line in f.ChangedContents():
1726 if log_call_pattern.search(line):
1727 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221728
1729 # Per file checks
1730 if has_modified_logs:
1731 # Make sure the tag is using the "cr" prefix and is not too long
1732 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511733 tag_name = match.group('name') if match else None
1734 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221735 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511736 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221737 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511738 elif '.' in tag_name:
1739 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221740
1741 results = []
1742 if tag_decl_errors:
1743 results.append(output_api.PresubmitPromptWarning(
1744 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511745 '"private static final String TAG = "<package tag>".\n'
1746 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221747 tag_decl_errors))
1748
1749 if tag_length_errors:
1750 results.append(output_api.PresubmitError(
1751 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511752 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221753 tag_length_errors))
1754
1755 if tag_errors:
1756 results.append(output_api.PresubmitPromptWarning(
1757 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1758 tag_errors))
1759
dgn87d9fb62015-06-12 09:15:121760 if util_log_errors:
dgn4401aa52015-04-29 16:26:171761 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121762 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1763 util_log_errors))
1764
dgn38736db2015-09-18 19:20:511765 if tag_with_dot_errors:
1766 results.append(output_api.PresubmitPromptWarning(
1767 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1768 tag_with_dot_errors))
1769
dgn4401aa52015-04-29 16:26:171770 return results
1771
1772
yolandyan45001472016-12-21 21:12:421773def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1774 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1775 deprecated_annotation_import_pattern = input_api.re.compile(
1776 r'^import android\.test\.suitebuilder\.annotation\..*;',
1777 input_api.re.MULTILINE)
1778 sources = lambda x: input_api.FilterSourceFile(
1779 x, white_list=(r'.*\.java$',), black_list=None)
1780 errors = []
1781 for f in input_api.AffectedFiles(sources):
1782 for line_num, line in f.ChangedContents():
1783 if deprecated_annotation_import_pattern.search(line):
1784 errors.append("%s:%d" % (f.LocalPath(), line_num))
1785
1786 results = []
1787 if errors:
1788 results.append(output_api.PresubmitError(
1789 'Annotations in android.test.suitebuilder.annotation have been'
1790 ' deprecated since API level 24. Please use android.support.test.filters'
1791 ' from //third_party/android_support_test_runner:runner_java instead.'
1792 ' Contact [email protected] if you have any questions.', errors))
1793 return results
1794
1795
agrieve7b6479d82015-10-07 14:24:221796def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1797 """Checks if MDPI assets are placed in a correct directory."""
1798 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1799 ('/res/drawable/' in f.LocalPath() or
1800 '/res/drawable-ldrtl/' in f.LocalPath()))
1801 errors = []
1802 for f in input_api.AffectedFiles(include_deletes=False,
1803 file_filter=file_filter):
1804 errors.append(' %s' % f.LocalPath())
1805
1806 results = []
1807 if errors:
1808 results.append(output_api.PresubmitError(
1809 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1810 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1811 '/res/drawable-ldrtl/.\n'
1812 'Contact [email protected] if you have questions.', errors))
1813 return results
1814
1815
agrievef32bcc72016-04-04 14:57:401816class PydepsChecker(object):
1817 def __init__(self, input_api, pydeps_files):
1818 self._file_cache = {}
1819 self._input_api = input_api
1820 self._pydeps_files = pydeps_files
1821
1822 def _LoadFile(self, path):
1823 """Returns the list of paths within a .pydeps file relative to //."""
1824 if path not in self._file_cache:
1825 with open(path) as f:
1826 self._file_cache[path] = f.read()
1827 return self._file_cache[path]
1828
1829 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1830 """Returns an interable of paths within the .pydep, relativized to //."""
1831 os_path = self._input_api.os_path
1832 pydeps_dir = os_path.dirname(pydeps_path)
1833 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1834 if not l.startswith('*'))
1835 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1836
1837 def _CreateFilesToPydepsMap(self):
1838 """Returns a map of local_path -> list_of_pydeps."""
1839 ret = {}
1840 for pydep_local_path in self._pydeps_files:
1841 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1842 ret.setdefault(path, []).append(pydep_local_path)
1843 return ret
1844
1845 def ComputeAffectedPydeps(self):
1846 """Returns an iterable of .pydeps files that might need regenerating."""
1847 affected_pydeps = set()
1848 file_to_pydeps_map = None
1849 for f in self._input_api.AffectedFiles(include_deletes=True):
1850 local_path = f.LocalPath()
1851 if local_path == 'DEPS':
1852 return self._pydeps_files
1853 elif local_path.endswith('.pydeps'):
1854 if local_path in self._pydeps_files:
1855 affected_pydeps.add(local_path)
1856 elif local_path.endswith('.py'):
1857 if file_to_pydeps_map is None:
1858 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1859 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1860 return affected_pydeps
1861
1862 def DetermineIfStale(self, pydeps_path):
1863 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411864 import difflib
agrievef32bcc72016-04-04 14:57:401865 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1866 cmd = old_pydeps_data[1][1:].strip()
1867 new_pydeps_data = self._input_api.subprocess.check_output(
1868 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411869 old_contents = old_pydeps_data[2:]
1870 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401871 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411872 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401873
1874
1875def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1876 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001877 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281878 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1879 # Mac, so skip it on other platforms.
1880 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001881 return []
agrievef32bcc72016-04-04 14:57:401882 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1883 is_android = input_api.os_path.exists('third_party/android_tools')
1884 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1885 results = []
1886 # First, check for new / deleted .pydeps.
1887 for f in input_api.AffectedFiles(include_deletes=True):
1888 if f.LocalPath().endswith('.pydeps'):
1889 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1890 results.append(output_api.PresubmitError(
1891 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1892 'remove %s' % f.LocalPath()))
1893 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1894 results.append(output_api.PresubmitError(
1895 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1896 'include %s' % f.LocalPath()))
1897
1898 if results:
1899 return results
1900
1901 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1902
1903 for pydep_path in checker.ComputeAffectedPydeps():
1904 try:
phajdan.jr0d9878552016-11-04 10:49:411905 result = checker.DetermineIfStale(pydep_path)
1906 if result:
1907 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401908 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411909 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1910 'To regenerate, run:\n\n %s' %
1911 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401912 except input_api.subprocess.CalledProcessError as error:
1913 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1914 long_text=error.output)]
1915
1916 return results
1917
1918
glidere61efad2015-02-18 17:39:431919def _CheckSingletonInHeaders(input_api, output_api):
1920 """Checks to make sure no header files have |Singleton<|."""
1921 def FileFilter(affected_file):
1922 # It's ok for base/memory/singleton.h to have |Singleton<|.
1923 black_list = (_EXCLUDED_PATHS +
1924 input_api.DEFAULT_BLACK_LIST +
1925 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1926 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1927
sergeyu34d21222015-09-16 00:11:441928 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431929 files = []
1930 for f in input_api.AffectedSourceFiles(FileFilter):
1931 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1932 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1933 contents = input_api.ReadFile(f)
1934 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241935 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431936 pattern.search(line)):
1937 files.append(f)
1938 break
1939
1940 if files:
yolandyandaabc6d2016-04-18 18:29:391941 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441942 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431943 'Please move them to an appropriate source file so that the ' +
1944 'template gets instantiated in a single compilation unit.',
1945 files) ]
1946 return []
1947
1948
dbeam1ec68ac2016-12-15 05:22:241949def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:201950 """Checks for old style compiled_resources.gyp files."""
1951 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1952
1953 added_compiled_resources = filter(is_compiled_resource, [
1954 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1955 ])
1956
1957 if not added_compiled_resources:
1958 return []
1959
1960 return [output_api.PresubmitError(
1961 "Found new compiled_resources.gyp files:\n%s\n\n"
1962 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551963 "please use compiled_resources2.gyp instead:\n"
1964 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1965 %
dbeam37e8e7402016-02-10 22:58:201966 "\n".join(added_compiled_resources))]
1967
1968
[email protected]fd20b902014-05-09 02:14:531969_DEPRECATED_CSS = [
1970 # Values
1971 ( "-webkit-box", "flex" ),
1972 ( "-webkit-inline-box", "inline-flex" ),
1973 ( "-webkit-flex", "flex" ),
1974 ( "-webkit-inline-flex", "inline-flex" ),
1975 ( "-webkit-min-content", "min-content" ),
1976 ( "-webkit-max-content", "max-content" ),
1977
1978 # Properties
1979 ( "-webkit-background-clip", "background-clip" ),
1980 ( "-webkit-background-origin", "background-origin" ),
1981 ( "-webkit-background-size", "background-size" ),
1982 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441983 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531984
1985 # Functions
1986 ( "-webkit-gradient", "gradient" ),
1987 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1988 ( "-webkit-linear-gradient", "linear-gradient" ),
1989 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1990 ( "-webkit-radial-gradient", "radial-gradient" ),
1991 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1992]
1993
dbeam1ec68ac2016-12-15 05:22:241994def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531995 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251996 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341997 documentation and iOS CSS for dom distiller
1998 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251999 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532000 results = []
dbeam070cfe62014-10-22 06:44:022001 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252002 black_list = (_EXCLUDED_PATHS +
2003 _TEST_CODE_EXCLUDED_PATHS +
2004 input_api.DEFAULT_BLACK_LIST +
2005 (r"^chrome/common/extensions/docs",
2006 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342007 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052008 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442009 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252010 r"^native_client_sdk"))
2011 file_filter = lambda f: input_api.FilterSourceFile(
2012 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532013 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2014 for line_num, line in fpath.ChangedContents():
2015 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022016 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532017 results.append(output_api.PresubmitError(
2018 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2019 (fpath.LocalPath(), line_num, deprecated_value, value)))
2020 return results
2021
mohan.reddyf21db962014-10-16 12:26:472022
dbeam070cfe62014-10-22 06:44:022023_DEPRECATED_JS = [
2024 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2025 ( "__defineGetter__", "Object.defineProperty" ),
2026 ( "__defineSetter__", "Object.defineProperty" ),
2027]
2028
dbeam1ec68ac2016-12-15 05:22:242029def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022030 """Make sure that we don't use deprecated JS in Chrome code."""
2031 results = []
2032 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2033 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2034 input_api.DEFAULT_BLACK_LIST)
2035 file_filter = lambda f: input_api.FilterSourceFile(
2036 f, white_list=file_inclusion_pattern, black_list=black_list)
2037 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2038 for lnum, line in fpath.ChangedContents():
2039 for (deprecated, replacement) in _DEPRECATED_JS:
2040 if deprecated in line:
2041 results.append(output_api.PresubmitError(
2042 "%s:%d: Use of deprecated JS %s, use %s instead" %
2043 (fpath.LocalPath(), lnum, deprecated, replacement)))
2044 return results
2045
2046
dbeam1ec68ac2016-12-15 05:22:242047def _CheckForRiskyJsFeatures(input_api, output_api):
2048 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2049 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2050
2051 arrow_lines = []
2052 for f in input_api.AffectedFiles(file_filter=file_filter):
2053 for lnum, line in f.ChangedContents():
2054 if ' => ' in line:
2055 arrow_lines.append((f.LocalPath(), lnum))
2056
2057 if not arrow_lines:
2058 return []
2059
2060 return [output_api.PresubmitPromptWarning("""
2061Use of => operator detected in:
2062%s
2063Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2064https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2065""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2066
2067
dgnaa68d5e2015-06-10 10:08:222068def _AndroidSpecificOnUploadChecks(input_api, output_api):
2069 """Groups checks that target android code."""
2070 results = []
dgnaa68d5e2015-06-10 10:08:222071 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222072 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292073 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422074 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222075 return results
2076
2077
[email protected]22c9bd72011-03-27 16:47:392078def _CommonChecks(input_api, output_api):
2079 """Checks common to both upload and commit."""
2080 results = []
2081 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382082 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542083 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582084 results.extend(
2085 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192086 results.extend(
[email protected]760deea2013-12-10 19:33:492087 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542088 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182089 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522090 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222091 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442092 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592093 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062094 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122095 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182096 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222097 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302098 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492099 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272100 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032101 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492102 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442103 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272104 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542105 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442106 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392107 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552108 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042109 results.extend(
2110 input_api.canned_checks.CheckChangeHasNoTabs(
2111 input_api,
2112 output_api,
2113 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402114 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162115 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592116 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082117 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242118 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2119 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472120 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042121 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232122 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432123 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242124 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402125 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152126 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172127 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502128 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242129 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242130
2131 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2132 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2133 input_api, output_api,
2134 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382135 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392136 return results
[email protected]1f7b4172010-01-28 01:17:342137
[email protected]b337cb5b2011-01-23 21:24:052138
[email protected]b8079ae4a2012-12-05 19:56:492139def _CheckPatchFiles(input_api, output_api):
2140 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2141 if f.LocalPath().endswith(('.orig', '.rej'))]
2142 if problems:
2143 return [output_api.PresubmitError(
2144 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032145 else:
2146 return []
[email protected]b8079ae4a2012-12-05 19:56:492147
2148
[email protected]b00342e7f2013-03-26 16:21:542149def _DidYouMeanOSMacro(bad_macro):
2150 try:
2151 return {'A': 'OS_ANDROID',
2152 'B': 'OS_BSD',
2153 'C': 'OS_CHROMEOS',
2154 'F': 'OS_FREEBSD',
2155 'L': 'OS_LINUX',
2156 'M': 'OS_MACOSX',
2157 'N': 'OS_NACL',
2158 'O': 'OS_OPENBSD',
2159 'P': 'OS_POSIX',
2160 'S': 'OS_SOLARIS',
2161 'W': 'OS_WIN'}[bad_macro[3].upper()]
2162 except KeyError:
2163 return ''
2164
2165
2166def _CheckForInvalidOSMacrosInFile(input_api, f):
2167 """Check for sensible looking, totally invalid OS macros."""
2168 preprocessor_statement = input_api.re.compile(r'^\s*#')
2169 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2170 results = []
2171 for lnum, line in f.ChangedContents():
2172 if preprocessor_statement.search(line):
2173 for match in os_macro.finditer(line):
2174 if not match.group(1) in _VALID_OS_MACROS:
2175 good = _DidYouMeanOSMacro(match.group(1))
2176 did_you_mean = ' (did you mean %s?)' % good if good else ''
2177 results.append(' %s:%d %s%s' % (f.LocalPath(),
2178 lnum,
2179 match.group(1),
2180 did_you_mean))
2181 return results
2182
2183
2184def _CheckForInvalidOSMacros(input_api, output_api):
2185 """Check all affected files for invalid OS macros."""
2186 bad_macros = []
2187 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472188 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542189 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2190
2191 if not bad_macros:
2192 return []
2193
2194 return [output_api.PresubmitError(
2195 'Possibly invalid OS macro[s] found. Please fix your code\n'
2196 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2197
lliabraa35bab3932014-10-01 12:16:442198
2199def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2200 """Check all affected files for invalid "if defined" macros."""
2201 ALWAYS_DEFINED_MACROS = (
2202 "TARGET_CPU_PPC",
2203 "TARGET_CPU_PPC64",
2204 "TARGET_CPU_68K",
2205 "TARGET_CPU_X86",
2206 "TARGET_CPU_ARM",
2207 "TARGET_CPU_MIPS",
2208 "TARGET_CPU_SPARC",
2209 "TARGET_CPU_ALPHA",
2210 "TARGET_IPHONE_SIMULATOR",
2211 "TARGET_OS_EMBEDDED",
2212 "TARGET_OS_IPHONE",
2213 "TARGET_OS_MAC",
2214 "TARGET_OS_UNIX",
2215 "TARGET_OS_WIN32",
2216 )
2217 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2218 results = []
2219 for lnum, line in f.ChangedContents():
2220 for match in ifdef_macro.finditer(line):
2221 if match.group(1) in ALWAYS_DEFINED_MACROS:
2222 always_defined = ' %s is always defined. ' % match.group(1)
2223 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2224 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2225 lnum,
2226 always_defined,
2227 did_you_mean))
2228 return results
2229
2230
2231def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2232 """Check all affected files for invalid "if defined" macros."""
2233 bad_macros = []
2234 for f in input_api.AffectedFiles():
2235 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2236 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2237
2238 if not bad_macros:
2239 return []
2240
2241 return [output_api.PresubmitError(
2242 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2243 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2244 bad_macros)]
2245
2246
mlamouria82272622014-09-16 18:45:042247def _CheckForIPCRules(input_api, output_api):
2248 """Check for same IPC rules described in
2249 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2250 """
2251 base_pattern = r'IPC_ENUM_TRAITS\('
2252 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2253 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2254
2255 problems = []
2256 for f in input_api.AffectedSourceFiles(None):
2257 local_path = f.LocalPath()
2258 if not local_path.endswith('.h'):
2259 continue
2260 for line_number, line in f.ChangedContents():
2261 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2262 problems.append(
2263 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2264
2265 if problems:
2266 return [output_api.PresubmitPromptWarning(
2267 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2268 else:
2269 return []
2270
[email protected]b00342e7f2013-03-26 16:21:542271
mostynbb639aca52015-01-07 20:31:232272def _CheckForWindowsLineEndings(input_api, output_api):
2273 """Check source code and known ascii text files for Windows style line
2274 endings.
2275 """
earthdok1b5e0ee2015-03-10 15:19:102276 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232277
2278 file_inclusion_pattern = (
2279 known_text_files,
2280 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2281 )
2282
2283 filter = lambda f: input_api.FilterSourceFile(
2284 f, white_list=file_inclusion_pattern, black_list=None)
2285 files = [f.LocalPath() for f in
2286 input_api.AffectedSourceFiles(filter)]
2287
2288 problems = []
2289
2290 for file in files:
2291 fp = open(file, 'r')
2292 for line in fp:
2293 if line.endswith('\r\n'):
2294 problems.append(file)
2295 break
2296 fp.close()
2297
2298 if problems:
2299 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2300 'these files to contain Windows style line endings?\n' +
2301 '\n'.join(problems))]
2302
2303 return []
2304
2305
pastarmovj89f7ee12016-09-20 14:58:132306def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2307 lint_filters=None, verbose_level=None):
2308 """Checks that all source files use SYSLOG properly."""
2309 syslog_files = []
2310 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562311 for line_number, line in f.ChangedContents():
2312 if 'SYSLOG' in line:
2313 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2314
pastarmovj89f7ee12016-09-20 14:58:132315 if syslog_files:
2316 return [output_api.PresubmitPromptWarning(
2317 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2318 ' calls.\nFiles to check:\n', items=syslog_files)]
2319 return []
2320
2321
[email protected]1f7b4172010-01-28 01:17:342322def CheckChangeOnUpload(input_api, output_api):
2323 results = []
2324 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472325 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282326 results.extend(
jam93a6ee792017-02-08 23:59:222327 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192328 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222329 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132330 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162331 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542332 return results
[email protected]ca8d1982009-02-19 16:33:122333
2334
[email protected]1bfb8322014-04-23 01:02:412335def GetTryServerMasterForBot(bot):
2336 """Returns the Try Server master for the given bot.
2337
[email protected]0bb112362014-07-26 04:38:322338 It tries to guess the master from the bot name, but may still fail
2339 and return None. There is no longer a default master.
2340 """
2341 # Potentially ambiguous bot names are listed explicitly.
2342 master_map = {
tandriie5587792016-07-14 00:34:502343 'chromium_presubmit': 'master.tryserver.chromium.linux',
2344 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412345 }
[email protected]0bb112362014-07-26 04:38:322346 master = master_map.get(bot)
2347 if not master:
wnwen4fbaab82016-05-25 12:54:362348 if 'android' in bot:
tandriie5587792016-07-14 00:34:502349 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362350 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502351 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322352 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502353 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322354 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502355 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322356 return master
[email protected]1bfb8322014-04-23 01:02:412357
2358
Paweł Hajdan, Jr55083782014-12-19 20:32:562359def GetDefaultTryConfigs(bots):
2360 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012361 """
2362
Paweł Hajdan, Jr55083782014-12-19 20:32:562363 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412364
2365 # Build up the mapping from tryserver master to bot/test.
2366 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562367 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412368 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2369 return out
[email protected]38c6a512013-12-18 23:48:012370
2371
[email protected]ca8d1982009-02-19 16:33:122372def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542373 results = []
[email protected]1f7b4172010-01-28 01:17:342374 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542375 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272376 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342377 input_api,
2378 output_api,
[email protected]2fdd1f362013-01-16 03:56:032379 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272380
jam93a6ee792017-02-08 23:59:222381 results.extend(
2382 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542383 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2384 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412385 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2386 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542387 return results