blob: 699a62b5a807a0b10882fec52c3322b01e408e61 [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$",
[email protected]4306417642009-06-11 00:33:4029)
[email protected]ca8d1982009-02-19 16:33:1230
wnwenbdc444e2016-05-25 13:44:1531
[email protected]06e6d0ff2012-12-11 01:36:4432# Fragment of a regular expression that matches C++ and Objective-C++
33# implementation files.
34_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
35
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Regular expression that matches code only used for test binaries
38# (best effort).
39_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4940 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4441 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5342 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1243 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4444 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4945 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0546 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4947 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4748 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4949 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0850 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4951 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4452)
[email protected]ca8d1982009-02-19 16:33:1253
wnwenbdc444e2016-05-25 13:44:1554
[email protected]eea609a2011-11-18 13:10:1255_TEST_ONLY_WARNING = (
56 'You might be calling functions intended only for testing from\n'
57 'production code. It is OK to ignore this warning if you know what\n'
58 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5859 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1260
61
[email protected]cf9b78f2012-11-14 11:40:2862_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4063 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2164 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
65 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2866
wnwenbdc444e2016-05-25 13:44:1567
[email protected]127f18ec2012-06-16 05:05:5968_BANNED_OBJC_FUNCTIONS = (
69 (
70 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2071 (
72 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5973 'prohibited. Please use CrTrackingArea instead.',
74 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
75 ),
76 False,
77 ),
78 (
[email protected]eaae1972014-04-16 04:17:2679 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2080 (
81 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5982 'instead.',
83 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
84 ),
85 False,
86 ),
87 (
88 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2089 (
90 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5991 'Please use |convertPoint:(point) fromView:nil| instead.',
92 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
93 ),
94 True,
95 ),
96 (
97 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2098 (
99 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59100 'Please use |convertPoint:(point) toView:nil| instead.',
101 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
102 ),
103 True,
104 ),
105 (
106 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20107 (
108 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59109 'Please use |convertRect:(point) fromView:nil| instead.',
110 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
111 ),
112 True,
113 ),
114 (
115 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20116 (
117 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59118 'Please use |convertRect:(point) toView:nil| instead.',
119 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
120 ),
121 True,
122 ),
123 (
124 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20125 (
126 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59127 'Please use |convertSize:(point) fromView:nil| instead.',
128 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
129 ),
130 True,
131 ),
132 (
133 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20134 (
135 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59136 'Please use |convertSize:(point) toView:nil| instead.',
137 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
138 ),
139 True,
140 ),
jif65398702016-10-27 10:19:48141 (
142 r"/\s+UTF8String\s*]",
143 (
144 'The use of -[NSString UTF8String] is dangerous as it can return null',
145 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
146 'Please use |SysNSStringToUTF8| instead.',
147 ),
148 True,
149 ),
[email protected]127f18ec2012-06-16 05:05:59150)
151
152
153_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20154 # Make sure that gtest's FRIEND_TEST() macro is not used; the
155 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30156 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20157 (
158 'FRIEND_TEST(',
159 (
[email protected]e3c945502012-06-26 20:01:49160 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20161 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
162 ),
163 False,
[email protected]7345da02012-11-27 14:31:49164 (),
[email protected]23e6cbc2012-06-16 18:51:20165 ),
166 (
thomasanderson4b569052016-09-14 20:15:53167 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
168 (
169 'Chrome clients wishing to select events on X windows should use',
170 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
171 'you are selecting events from the GPU process, or if you are using',
172 'an XDisplay other than gfx::GetXDisplay().',
173 ),
174 True,
175 (
176 r"^ui[\\\/]gl[\\\/].*\.cc$",
177 r"^media[\\\/]gpu[\\\/].*\.cc$",
178 r"^gpu[\\\/].*\.cc$",
179 ),
180 ),
181 (
[email protected]23e6cbc2012-06-16 18:51:20182 'ScopedAllowIO',
183 (
[email protected]e3c945502012-06-26 20:01:49184 'New code should not use ScopedAllowIO. Post a task to the blocking',
185 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20186 ),
[email protected]e3c945502012-06-26 20:01:49187 True,
[email protected]7345da02012-11-27 14:31:49188 (
hajimehoshi2acea432017-03-08 08:55:37189 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
nyad2c548b2015-12-09 03:22:32190 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10191 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22192 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31193 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51194 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
195 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09196 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49197 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
198 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25199 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41200 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
201 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25202 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48203 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
204 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01205 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25206 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
207 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
208 r"embedded_test_server\.cc$",
209 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
210 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54211 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16212 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53213 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
214 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45215 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
216 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
217 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
218 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
219 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49220 ),
[email protected]23e6cbc2012-06-16 18:51:20221 ),
[email protected]52657f62013-05-20 05:30:31222 (
tomhudsone2c14d552016-05-26 17:07:46223 'setMatrixClip',
224 (
225 'Overriding setMatrixClip() is prohibited; ',
226 'the base function is deprecated. ',
227 ),
228 True,
229 (),
230 ),
231 (
[email protected]52657f62013-05-20 05:30:31232 'SkRefPtr',
233 (
234 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22235 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31236 ),
237 True,
238 (),
239 ),
240 (
241 'SkAutoRef',
242 (
243 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22244 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31245 ),
246 True,
247 (),
248 ),
249 (
250 'SkAutoTUnref',
251 (
252 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22253 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31254 ),
255 True,
256 (),
257 ),
258 (
259 'SkAutoUnref',
260 (
261 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
262 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22263 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31264 ),
265 True,
266 (),
267 ),
[email protected]d89eec82013-12-03 14:10:59268 (
269 r'/HANDLE_EINTR\(.*close',
270 (
271 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
272 'descriptor will be closed, and it is incorrect to retry the close.',
273 'Either call close directly and ignore its return value, or wrap close',
274 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
275 ),
276 True,
277 (),
278 ),
279 (
280 r'/IGNORE_EINTR\((?!.*close)',
281 (
282 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
283 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
284 ),
285 True,
286 (
287 # Files that #define IGNORE_EINTR.
288 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
289 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
290 ),
291 ),
[email protected]ec5b3f02014-04-04 18:43:43292 (
293 r'/v8::Extension\(',
294 (
295 'Do not introduce new v8::Extensions into the code base, use',
296 'gin::Wrappable instead. See http://crbug.com/334679',
297 ),
298 True,
[email protected]f55c90ee62014-04-12 00:50:03299 (
joaodasilva718f87672014-08-30 09:25:49300 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03301 ),
[email protected]ec5b3f02014-04-04 18:43:43302 ),
skyostilf9469f72015-04-20 10:38:52303 (
jame2d1a952016-04-02 00:27:10304 '#pragma comment(lib,',
305 (
306 'Specify libraries to link with in build files and not in the source.',
307 ),
308 True,
309 (),
310 ),
[email protected]127f18ec2012-06-16 05:05:59311)
312
wnwenbdc444e2016-05-25 13:44:15313
mlamouria82272622014-09-16 18:45:04314_IPC_ENUM_TRAITS_DEPRECATED = (
315 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
316 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
317
[email protected]127f18ec2012-06-16 05:05:59318
[email protected]b00342e7f2013-03-26 16:21:54319_VALID_OS_MACROS = (
320 # Please keep sorted.
321 'OS_ANDROID',
322 'OS_BSD',
323 'OS_CAT', # For testing.
324 'OS_CHROMEOS',
325 'OS_FREEBSD',
326 'OS_IOS',
327 'OS_LINUX',
328 'OS_MACOSX',
329 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21330 'OS_NACL_NONSFI',
331 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12332 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54333 'OS_OPENBSD',
334 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37335 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54336 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54337 'OS_WIN',
338)
339
340
agrievef32bcc72016-04-04 14:57:40341_ANDROID_SPECIFIC_PYDEPS_FILES = [
342 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19343 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40344]
345
wnwenbdc444e2016-05-25 13:44:15346
agrievef32bcc72016-04-04 14:57:40347_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40348]
349
wnwenbdc444e2016-05-25 13:44:15350
agrievef32bcc72016-04-04 14:57:40351_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
352
353
[email protected]55459852011-08-10 15:17:19354def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
355 """Attempts to prevent use of functions intended only for testing in
356 non-testing code. For now this is just a best-effort implementation
357 that ignores header files and may have some false positives. A
358 better implementation would probably need a proper C++ parser.
359 """
360 # We only scan .cc files and the like, as the declaration of
361 # for-testing functions in header files are hard to distinguish from
362 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44363 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19364
jochenc0d4808c2015-07-27 09:25:42365 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19366 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09367 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19368 exclusion_pattern = input_api.re.compile(
369 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
370 base_function_pattern, base_function_pattern))
371
372 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44373 black_list = (_EXCLUDED_PATHS +
374 _TEST_CODE_EXCLUDED_PATHS +
375 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19376 return input_api.FilterSourceFile(
377 affected_file,
378 white_list=(file_inclusion_pattern, ),
379 black_list=black_list)
380
381 problems = []
382 for f in input_api.AffectedSourceFiles(FilterFile):
383 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24384 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03385 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46386 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03387 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19388 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03389 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19390
391 if problems:
[email protected]f7051d52013-04-02 18:31:42392 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03393 else:
394 return []
[email protected]55459852011-08-10 15:17:19395
396
[email protected]10689ca2011-09-02 02:31:54397def _CheckNoIOStreamInHeaders(input_api, output_api):
398 """Checks to make sure no .h files include <iostream>."""
399 files = []
400 pattern = input_api.re.compile(r'^#include\s*<iostream>',
401 input_api.re.MULTILINE)
402 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
403 if not f.LocalPath().endswith('.h'):
404 continue
405 contents = input_api.ReadFile(f)
406 if pattern.search(contents):
407 files.append(f)
408
409 if len(files):
yolandyandaabc6d2016-04-18 18:29:39410 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06411 'Do not #include <iostream> in header files, since it inserts static '
412 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54413 '#include <ostream>. See http://crbug.com/94794',
414 files) ]
415 return []
416
417
[email protected]72df4e782012-06-21 16:28:18418def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52419 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18420 problems = []
421 for f in input_api.AffectedFiles():
422 if (not f.LocalPath().endswith(('.cc', '.mm'))):
423 continue
424
425 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04426 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18427 problems.append(' %s:%d' % (f.LocalPath(), line_num))
428
429 if not problems:
430 return []
431 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
432 '\n'.join(problems))]
433
434
danakj61c1aa22015-10-26 19:55:52435def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57436 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52437 errors = []
438 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
439 input_api.re.MULTILINE)
440 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
441 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
442 continue
443 for lnum, line in f.ChangedContents():
444 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17445 errors.append(output_api.PresubmitError(
446 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57447 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17448 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52449 return errors
450
451
mcasasb7440c282015-02-04 14:52:19452def _FindHistogramNameInLine(histogram_name, line):
453 """Tries to find a histogram name or prefix in a line."""
454 if not "affected-histogram" in line:
455 return histogram_name in line
456 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
457 # the histogram_name.
458 if not '"' in line:
459 return False
460 histogram_prefix = line.split('\"')[1]
461 return histogram_prefix in histogram_name
462
463
464def _CheckUmaHistogramChanges(input_api, output_api):
465 """Check that UMA histogram names in touched lines can still be found in other
466 lines of the patch or in histograms.xml. Note that this check would not catch
467 the reverse: changes in histograms.xml not matched in the code itself."""
468 touched_histograms = []
469 histograms_xml_modifications = []
470 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
471 for f in input_api.AffectedFiles():
472 # If histograms.xml itself is modified, keep the modified lines for later.
473 if f.LocalPath().endswith(('histograms.xml')):
474 histograms_xml_modifications = f.ChangedContents()
475 continue
476 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
477 continue
478 for line_num, line in f.ChangedContents():
479 found = pattern.search(line)
480 if found:
481 touched_histograms.append([found.group(1), f, line_num])
482
483 # Search for the touched histogram names in the local modifications to
484 # histograms.xml, and, if not found, on the base histograms.xml file.
485 unmatched_histograms = []
486 for histogram_info in touched_histograms:
487 histogram_name_found = False
488 for line_num, line in histograms_xml_modifications:
489 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
490 if histogram_name_found:
491 break
492 if not histogram_name_found:
493 unmatched_histograms.append(histogram_info)
494
eromanb90c82e7e32015-04-01 15:13:49495 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19496 problems = []
497 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49498 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19499 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45500 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19501 histogram_name_found = False
502 for line in histograms_xml:
503 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
504 if histogram_name_found:
505 break
506 if not histogram_name_found:
507 problems.append(' [%s:%d] %s' %
508 (f.LocalPath(), line_num, histogram_name))
509
510 if not problems:
511 return []
512 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
513 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49514 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19515
wnwenbdc444e2016-05-25 13:44:15516
yolandyandaabc6d2016-04-18 18:29:39517def _CheckFlakyTestUsage(input_api, output_api):
518 """Check that FlakyTest annotation is our own instead of the android one"""
519 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
520 files = []
521 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
522 if f.LocalPath().endswith('Test.java'):
523 if pattern.search(input_api.ReadFile(f)):
524 files.append(f)
525 if len(files):
526 return [output_api.PresubmitError(
527 'Use org.chromium.base.test.util.FlakyTest instead of '
528 'android.test.FlakyTest',
529 files)]
530 return []
mcasasb7440c282015-02-04 14:52:19531
wnwenbdc444e2016-05-25 13:44:15532
[email protected]8ea5d4b2011-09-13 21:49:22533def _CheckNoNewWStrings(input_api, output_api):
534 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27535 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22536 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20537 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57538 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34539 '/win/' in f.LocalPath() or
540 'chrome_elf' in f.LocalPath() or
541 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20542 continue
[email protected]8ea5d4b2011-09-13 21:49:22543
[email protected]a11dbe9b2012-08-07 01:32:58544 allowWString = False
[email protected]b5c24292011-11-28 14:38:20545 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58546 if 'presubmit: allow wstring' in line:
547 allowWString = True
548 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27549 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58550 allowWString = False
551 else:
552 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22553
[email protected]55463aa62011-10-12 00:48:27554 if not problems:
555 return []
556 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58557 ' If you are calling a cross-platform API that accepts a wstring, '
558 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27559 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22560
561
[email protected]2a8ac9c2011-10-19 17:20:44562def _CheckNoDEPSGIT(input_api, output_api):
563 """Make sure .DEPS.git is never modified manually."""
564 if any(f.LocalPath().endswith('.DEPS.git') for f in
565 input_api.AffectedFiles()):
566 return [output_api.PresubmitError(
567 'Never commit changes to .DEPS.git. This file is maintained by an\n'
568 'automated system based on what\'s in DEPS and your changes will be\n'
569 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34570 '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:44571 'for more information')]
572 return []
573
574
tandriief664692014-09-23 14:51:47575def _CheckValidHostsInDEPS(input_api, output_api):
576 """Checks that DEPS file deps are from allowed_hosts."""
577 # Run only if DEPS file has been modified to annoy fewer bystanders.
578 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
579 return []
580 # Outsource work to gclient verify
581 try:
582 input_api.subprocess.check_output(['gclient', 'verify'])
583 return []
584 except input_api.subprocess.CalledProcessError, error:
585 return [output_api.PresubmitError(
586 'DEPS file must have only git dependencies.',
587 long_text=error.output)]
588
589
[email protected]127f18ec2012-06-16 05:05:59590def _CheckNoBannedFunctions(input_api, output_api):
591 """Make sure that banned functions are not used."""
592 warnings = []
593 errors = []
594
wnwenbdc444e2016-05-25 13:44:15595 def IsBlacklisted(affected_file, blacklist):
596 local_path = affected_file.LocalPath()
597 for item in blacklist:
598 if input_api.re.match(item, local_path):
599 return True
600 return False
601
602 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
603 matched = False
604 if func_name[0:1] == '/':
605 regex = func_name[1:]
606 if input_api.re.search(regex, line):
607 matched = True
608 elif func_name in line:
dchenge07de812016-06-20 19:27:17609 matched = True
wnwenbdc444e2016-05-25 13:44:15610 if matched:
dchenge07de812016-06-20 19:27:17611 problems = warnings
wnwenbdc444e2016-05-25 13:44:15612 if error:
dchenge07de812016-06-20 19:27:17613 problems = errors
wnwenbdc444e2016-05-25 13:44:15614 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
615 for message_line in message:
616 problems.append(' %s' % message_line)
617
[email protected]127f18ec2012-06-16 05:05:59618 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
619 for f in input_api.AffectedFiles(file_filter=file_filter):
620 for line_num, line in f.ChangedContents():
621 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15622 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59623
624 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
625 for f in input_api.AffectedFiles(file_filter=file_filter):
626 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49627 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49628 if IsBlacklisted(f, excluded_paths):
629 continue
wnwenbdc444e2016-05-25 13:44:15630 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59631
632 result = []
633 if (warnings):
634 result.append(output_api.PresubmitPromptWarning(
635 'Banned functions were used.\n' + '\n'.join(warnings)))
636 if (errors):
637 result.append(output_api.PresubmitError(
638 'Banned functions were used.\n' + '\n'.join(errors)))
639 return result
640
641
[email protected]6c063c62012-07-11 19:11:06642def _CheckNoPragmaOnce(input_api, output_api):
643 """Make sure that banned functions are not used."""
644 files = []
645 pattern = input_api.re.compile(r'^#pragma\s+once',
646 input_api.re.MULTILINE)
647 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
648 if not f.LocalPath().endswith('.h'):
649 continue
650 contents = input_api.ReadFile(f)
651 if pattern.search(contents):
652 files.append(f)
653
654 if files:
655 return [output_api.PresubmitError(
656 'Do not use #pragma once in header files.\n'
657 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
658 files)]
659 return []
660
[email protected]127f18ec2012-06-16 05:05:59661
[email protected]e7479052012-09-19 00:26:12662def _CheckNoTrinaryTrueFalse(input_api, output_api):
663 """Checks to make sure we don't introduce use of foo ? true : false."""
664 problems = []
665 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
666 for f in input_api.AffectedFiles():
667 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
668 continue
669
670 for line_num, line in f.ChangedContents():
671 if pattern.match(line):
672 problems.append(' %s:%d' % (f.LocalPath(), line_num))
673
674 if not problems:
675 return []
676 return [output_api.PresubmitPromptWarning(
677 'Please consider avoiding the "? true : false" pattern if possible.\n' +
678 '\n'.join(problems))]
679
680
[email protected]55f9f382012-07-31 11:02:18681def _CheckUnwantedDependencies(input_api, output_api):
682 """Runs checkdeps on #include statements added in this
683 change. Breaking - rules is an error, breaking ! rules is a
684 warning.
685 """
mohan.reddyf21db962014-10-16 12:26:47686 import sys
[email protected]55f9f382012-07-31 11:02:18687 # We need to wait until we have an input_api object and use this
688 # roundabout construct to import checkdeps because this file is
689 # eval-ed and thus doesn't have __file__.
690 original_sys_path = sys.path
691 try:
692 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47693 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18694 import checkdeps
695 from cpp_checker import CppChecker
696 from rules import Rule
697 finally:
698 # Restore sys.path to what it was before.
699 sys.path = original_sys_path
700
701 added_includes = []
702 for f in input_api.AffectedFiles():
703 if not CppChecker.IsCppFile(f.LocalPath()):
704 continue
705
706 changed_lines = [line for line_num, line in f.ChangedContents()]
707 added_includes.append([f.LocalPath(), changed_lines])
708
[email protected]26385172013-05-09 23:11:35709 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18710
711 error_descriptions = []
712 warning_descriptions = []
713 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
714 added_includes):
715 description_with_path = '%s\n %s' % (path, rule_description)
716 if rule_type == Rule.DISALLOW:
717 error_descriptions.append(description_with_path)
718 else:
719 warning_descriptions.append(description_with_path)
720
721 results = []
722 if error_descriptions:
723 results.append(output_api.PresubmitError(
724 'You added one or more #includes that violate checkdeps rules.',
725 error_descriptions))
726 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42727 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18728 'You added one or more #includes of files that are temporarily\n'
729 'allowed but being removed. Can you avoid introducing the\n'
730 '#include? See relevant DEPS file(s) for details and contacts.',
731 warning_descriptions))
732 return results
733
734
[email protected]fbcafe5a2012-08-08 15:31:22735def _CheckFilePermissions(input_api, output_api):
736 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15737 if input_api.platform == 'win32':
738 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29739 checkperms_tool = input_api.os_path.join(
740 input_api.PresubmitLocalPath(),
741 'tools', 'checkperms', 'checkperms.py')
742 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47743 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22744 for f in input_api.AffectedFiles():
745 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11746 try:
747 input_api.subprocess.check_output(args)
748 return []
749 except input_api.subprocess.CalledProcessError as error:
750 return [output_api.PresubmitError(
751 'checkperms.py failed:',
752 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22753
754
robertocn832f5992017-01-04 19:01:30755def _CheckTeamTags(input_api, output_api):
756 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
757 checkteamtags_tool = input_api.os_path.join(
758 input_api.PresubmitLocalPath(),
759 'tools', 'checkteamtags', 'checkteamtags.py')
760 args = [input_api.python_executable, checkteamtags_tool,
761 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22762 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30763 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
764 'OWNERS']
765 try:
766 if files:
767 input_api.subprocess.check_output(args + files)
768 return []
769 except input_api.subprocess.CalledProcessError as error:
770 return [output_api.PresubmitError(
771 'checkteamtags.py failed:',
772 long_text=error.output)]
773
774
[email protected]c8278b32012-10-30 20:35:49775def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
776 """Makes sure we don't include ui/aura/window_property.h
777 in header files.
778 """
779 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
780 errors = []
781 for f in input_api.AffectedFiles():
782 if not f.LocalPath().endswith('.h'):
783 continue
784 for line_num, line in f.ChangedContents():
785 if pattern.match(line):
786 errors.append(' %s:%d' % (f.LocalPath(), line_num))
787
788 results = []
789 if errors:
790 results.append(output_api.PresubmitError(
791 'Header files should not include ui/aura/window_property.h', errors))
792 return results
793
794
[email protected]cf9b78f2012-11-14 11:40:28795def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
796 """Checks that the lines in scope occur in the right order.
797
798 1. C system files in alphabetical order
799 2. C++ system files in alphabetical order
800 3. Project's .h files
801 """
802
803 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
804 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
805 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
806
807 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
808
809 state = C_SYSTEM_INCLUDES
810
811 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57812 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28813 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55814 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28815 for line_num, line in scope:
816 if c_system_include_pattern.match(line):
817 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55818 problem_linenums.append((line_num, previous_line_num,
819 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28820 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55821 problem_linenums.append((line_num, previous_line_num,
822 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28823 elif cpp_system_include_pattern.match(line):
824 if state == C_SYSTEM_INCLUDES:
825 state = CPP_SYSTEM_INCLUDES
826 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55827 problem_linenums.append((line_num, previous_line_num,
828 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28829 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55830 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28831 elif custom_include_pattern.match(line):
832 if state != CUSTOM_INCLUDES:
833 state = CUSTOM_INCLUDES
834 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55835 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28836 else:
brucedawson70fadb02015-06-30 17:47:55837 problem_linenums.append((line_num, previous_line_num,
838 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28839 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57840 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28841
842 warnings = []
brucedawson70fadb02015-06-30 17:47:55843 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57844 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55845 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28846 return warnings
847
848
[email protected]ac294a12012-12-06 16:38:43849def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28850 """Checks the #include order for the given file f."""
851
[email protected]2299dcf2012-11-15 19:56:24852 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30853 # Exclude the following includes from the check:
854 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
855 # specific order.
856 # 2) <atlbase.h>, "build/build_config.h"
857 excluded_include_pattern = input_api.re.compile(
858 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24859 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33860 # Match the final or penultimate token if it is xxxtest so we can ignore it
861 # when considering the special first include.
862 test_file_tag_pattern = input_api.re.compile(
863 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11864 if_pattern = input_api.re.compile(
865 r'\s*#\s*(if|elif|else|endif|define|undef).*')
866 # Some files need specialized order of includes; exclude such files from this
867 # check.
868 uncheckable_includes_pattern = input_api.re.compile(
869 r'\s*#include '
870 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28871
872 contents = f.NewContents()
873 warnings = []
874 line_num = 0
875
[email protected]ac294a12012-12-06 16:38:43876 # Handle the special first include. If the first include file is
877 # some/path/file.h, the corresponding including file can be some/path/file.cc,
878 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
879 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33880 # If the included file is some/path/file_platform.h the including file could
881 # also be some/path/file_xxxtest_platform.h.
882 including_file_base_name = test_file_tag_pattern.sub(
883 '', input_api.os_path.basename(f.LocalPath()))
884
[email protected]ac294a12012-12-06 16:38:43885 for line in contents:
886 line_num += 1
887 if system_include_pattern.match(line):
888 # No special first include -> process the line again along with normal
889 # includes.
890 line_num -= 1
891 break
892 match = custom_include_pattern.match(line)
893 if match:
894 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33895 header_basename = test_file_tag_pattern.sub(
896 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
897
898 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24899 # No special first include -> process the line again along with normal
900 # includes.
901 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43902 break
[email protected]cf9b78f2012-11-14 11:40:28903
904 # Split into scopes: Each region between #if and #endif is its own scope.
905 scopes = []
906 current_scope = []
907 for line in contents[line_num:]:
908 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11909 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54910 continue
[email protected]2309b0fa02012-11-16 12:18:27911 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28912 scopes.append(current_scope)
913 current_scope = []
[email protected]962f117e2012-11-22 18:11:56914 elif ((system_include_pattern.match(line) or
915 custom_include_pattern.match(line)) and
916 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28917 current_scope.append((line_num, line))
918 scopes.append(current_scope)
919
920 for scope in scopes:
921 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
922 changed_linenums))
923 return warnings
924
925
926def _CheckIncludeOrder(input_api, output_api):
927 """Checks that the #include order is correct.
928
929 1. The corresponding header for source files.
930 2. C system files in alphabetical order
931 3. C++ system files in alphabetical order
932 4. Project's .h files in alphabetical order
933
[email protected]ac294a12012-12-06 16:38:43934 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
935 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28936 """
[email protected]e120b012014-08-15 19:08:35937 def FileFilterIncludeOrder(affected_file):
938 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
939 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28940
941 warnings = []
[email protected]e120b012014-08-15 19:08:35942 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08943 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43944 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
945 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28946
947 results = []
948 if warnings:
[email protected]f7051d52013-04-02 18:31:42949 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53950 warnings))
[email protected]cf9b78f2012-11-14 11:40:28951 return results
952
953
[email protected]70ca77752012-11-20 03:45:03954def _CheckForVersionControlConflictsInFile(input_api, f):
955 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
956 errors = []
957 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23958 if f.LocalPath().endswith('.md'):
959 # First-level headers in markdown look a lot like version control
960 # conflict markers. http://daringfireball.net/projects/markdown/basics
961 continue
[email protected]70ca77752012-11-20 03:45:03962 if pattern.match(line):
963 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
964 return errors
965
966
967def _CheckForVersionControlConflicts(input_api, output_api):
968 """Usually this is not intentional and will cause a compile failure."""
969 errors = []
970 for f in input_api.AffectedFiles():
971 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
972
973 results = []
974 if errors:
975 results.append(output_api.PresubmitError(
976 'Version control conflict markers found, please resolve.', errors))
977 return results
978
estadee17314a02017-01-12 16:22:16979def _CheckGoogleSupportAnswerUrl(input_api, output_api):
980 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
981 errors = []
982 for f in input_api.AffectedFiles():
983 for line_num, line in f.ChangedContents():
984 if pattern.search(line):
985 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
986
987 results = []
988 if errors:
989 results.append(output_api.PresubmitPromptWarning(
990 'Found Google support URL addressed by answer number. Please replace with '
991 'a p= identifier instead. See crbug.com/679462\n', errors))
992 return results
993
[email protected]70ca77752012-11-20 03:45:03994
[email protected]06e6d0ff2012-12-11 01:36:44995def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
996 def FilterFile(affected_file):
997 """Filter function for use with input_api.AffectedSourceFiles,
998 below. This filters out everything except non-test files from
999 top-level directories that generally speaking should not hard-code
1000 service URLs (e.g. src/android_webview/, src/content/ and others).
1001 """
1002 return input_api.FilterSourceFile(
1003 affected_file,
[email protected]78bb39d62012-12-11 15:11:561004 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441005 black_list=(_EXCLUDED_PATHS +
1006 _TEST_CODE_EXCLUDED_PATHS +
1007 input_api.DEFAULT_BLACK_LIST))
1008
reillyi38965732015-11-16 18:27:331009 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1010 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461011 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1012 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441013 problems = [] # items are (filename, line_number, line)
1014 for f in input_api.AffectedSourceFiles(FilterFile):
1015 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461016 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441017 problems.append((f.LocalPath(), line_num, line))
1018
1019 if problems:
[email protected]f7051d52013-04-02 18:31:421020 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441021 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581022 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441023 [' %s:%d: %s' % (
1024 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031025 else:
1026 return []
[email protected]06e6d0ff2012-12-11 01:36:441027
1028
[email protected]d2530012013-01-25 16:39:271029def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1030 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311031 The native_client_sdk directory is excluded because it has auto-generated PNG
1032 files for documentation.
[email protected]d2530012013-01-25 16:39:271033 """
[email protected]d2530012013-01-25 16:39:271034 errors = []
binji0dcdf342014-12-12 18:32:311035 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1036 black_list = (r'^native_client_sdk[\\\/]',)
1037 file_filter = lambda f: input_api.FilterSourceFile(
1038 f, white_list=white_list, black_list=black_list)
1039 for f in input_api.AffectedFiles(include_deletes=False,
1040 file_filter=file_filter):
1041 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271042
1043 results = []
1044 if errors:
1045 results.append(output_api.PresubmitError(
1046 'The name of PNG files should not have abbreviations. \n'
1047 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1048 'Contact [email protected] if you have questions.', errors))
1049 return results
1050
1051
[email protected]14a6131c2014-01-08 01:15:411052def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:081053 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411054 a set of DEPS entries that we should look up.
1055
1056 For a directory (rather than a specific filename) we fake a path to
1057 a specific filename by adding /DEPS. This is chosen as a file that
1058 will seldom or never be subject to per-file include_rules.
1059 """
[email protected]2b438d62013-11-14 17:54:141060 # We ignore deps entries on auto-generated directories.
1061 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081062
1063 # This pattern grabs the path without basename in the first
1064 # parentheses, and the basename (if present) in the second. It
1065 # relies on the simple heuristic that if there is a basename it will
1066 # be a header file ending in ".h".
1067 pattern = re.compile(
1068 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141069 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081070 for changed_line in changed_lines:
1071 m = pattern.match(changed_line)
1072 if m:
1073 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141074 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411075 if m.group(2):
1076 results.add('%s%s' % (path, m.group(2)))
1077 else:
1078 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081079 return results
1080
1081
[email protected]e871964c2013-05-13 14:14:551082def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1083 """When a dependency prefixed with + is added to a DEPS file, we
1084 want to make sure that the change is reviewed by an OWNER of the
1085 target file or directory, to avoid layering violations from being
1086 introduced. This check verifies that this happens.
1087 """
1088 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241089
1090 file_filter = lambda f: not input_api.re.match(
1091 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1092 for f in input_api.AffectedFiles(include_deletes=False,
1093 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551094 filename = input_api.os_path.basename(f.LocalPath())
1095 if filename == 'DEPS':
1096 changed_lines |= set(line.strip()
1097 for line_num, line
1098 in f.ChangedContents())
1099 if not changed_lines:
1100 return []
1101
[email protected]14a6131c2014-01-08 01:15:411102 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1103 changed_lines)
[email protected]e871964c2013-05-13 14:14:551104 if not virtual_depended_on_files:
1105 return []
1106
1107 if input_api.is_committing:
1108 if input_api.tbr:
1109 return [output_api.PresubmitNotifyResult(
1110 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271111 if input_api.dry_run:
1112 return [output_api.PresubmitNotifyResult(
1113 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551114 if not input_api.change.issue:
1115 return [output_api.PresubmitError(
1116 "DEPS approval by OWNERS check failed: this change has "
1117 "no Rietveld issue number, so we can't check it for approvals.")]
1118 output = output_api.PresubmitError
1119 else:
1120 output = output_api.PresubmitNotifyResult
1121
1122 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501123 owner_email, reviewers = (
1124 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1125 input_api,
1126 owners_db.email_regexp,
1127 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551128
1129 owner_email = owner_email or input_api.change.author_email
1130
[email protected]de4f7d22013-05-23 14:27:461131 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511132 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461133 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551134 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1135 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411136
1137 # We strip the /DEPS part that was added by
1138 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1139 # directory.
1140 def StripDeps(path):
1141 start_deps = path.rfind('/DEPS')
1142 if start_deps != -1:
1143 return path[:start_deps]
1144 else:
1145 return path
1146 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551147 for path in missing_files]
1148
1149 if unapproved_dependencies:
1150 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151151 output('You need LGTM from owners of depends-on paths in DEPS that were '
1152 'modified in this CL:\n %s' %
1153 '\n '.join(sorted(unapproved_dependencies)))]
1154 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1155 output_list.append(output(
1156 'Suggested missing target path OWNERS:\n %s' %
1157 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551158 return output_list
1159
1160 return []
1161
1162
[email protected]85218562013-11-22 07:41:401163def _CheckSpamLogging(input_api, output_api):
1164 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1165 black_list = (_EXCLUDED_PATHS +
1166 _TEST_CODE_EXCLUDED_PATHS +
1167 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501168 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191169 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481170 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461171 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121172 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1173 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581174 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161175 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031176 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151177 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1178 r"^chromecast[\\\/]",
1179 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311180 r"^components[\\\/]html_viewer[\\\/]"
1181 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461182 # TODO(peter): Remove this exception. https://crbug.com/534537
1183 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1184 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251185 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1186 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241187 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111188 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151189 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111190 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521191 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501192 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361193 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311194 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131195 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001196 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441197 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451198 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021199 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351200 r"dump_file_system.cc$",
1201 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401202 source_file_filter = lambda x: input_api.FilterSourceFile(
1203 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1204
1205 log_info = []
1206 printf = []
1207
1208 for f in input_api.AffectedSourceFiles(source_file_filter):
1209 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471210 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401211 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471212 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131213 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371214
mohan.reddyf21db962014-10-16 12:26:471215 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371216 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471217 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401218 printf.append(f.LocalPath())
1219
1220 if log_info:
1221 return [output_api.PresubmitError(
1222 'These files spam the console log with LOG(INFO):',
1223 items=log_info)]
1224 if printf:
1225 return [output_api.PresubmitError(
1226 'These files spam the console log with printf/fprintf:',
1227 items=printf)]
1228 return []
1229
1230
[email protected]49aa76a2013-12-04 06:59:161231def _CheckForAnonymousVariables(input_api, output_api):
1232 """These types are all expected to hold locks while in scope and
1233 so should never be anonymous (which causes them to be immediately
1234 destroyed)."""
1235 they_who_must_be_named = [
1236 'base::AutoLock',
1237 'base::AutoReset',
1238 'base::AutoUnlock',
1239 'SkAutoAlphaRestore',
1240 'SkAutoBitmapShaderInstall',
1241 'SkAutoBlitterChoose',
1242 'SkAutoBounderCommit',
1243 'SkAutoCallProc',
1244 'SkAutoCanvasRestore',
1245 'SkAutoCommentBlock',
1246 'SkAutoDescriptor',
1247 'SkAutoDisableDirectionCheck',
1248 'SkAutoDisableOvalCheck',
1249 'SkAutoFree',
1250 'SkAutoGlyphCache',
1251 'SkAutoHDC',
1252 'SkAutoLockColors',
1253 'SkAutoLockPixels',
1254 'SkAutoMalloc',
1255 'SkAutoMaskFreeImage',
1256 'SkAutoMutexAcquire',
1257 'SkAutoPathBoundsUpdate',
1258 'SkAutoPDFRelease',
1259 'SkAutoRasterClipValidate',
1260 'SkAutoRef',
1261 'SkAutoTime',
1262 'SkAutoTrace',
1263 'SkAutoUnref',
1264 ]
1265 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1266 # bad: base::AutoLock(lock.get());
1267 # not bad: base::AutoLock lock(lock.get());
1268 bad_pattern = input_api.re.compile(anonymous)
1269 # good: new base::AutoLock(lock.get())
1270 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1271 errors = []
1272
1273 for f in input_api.AffectedFiles():
1274 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1275 continue
1276 for linenum, line in f.ChangedContents():
1277 if bad_pattern.search(line) and not good_pattern.search(line):
1278 errors.append('%s:%d' % (f.LocalPath(), linenum))
1279
1280 if errors:
1281 return [output_api.PresubmitError(
1282 'These lines create anonymous variables that need to be named:',
1283 items=errors)]
1284 return []
1285
1286
[email protected]5fe0f8742013-11-29 01:04:591287def _CheckCygwinShell(input_api, output_api):
1288 source_file_filter = lambda x: input_api.FilterSourceFile(
1289 x, white_list=(r'.+\.(gyp|gypi)$',))
1290 cygwin_shell = []
1291
1292 for f in input_api.AffectedSourceFiles(source_file_filter):
1293 for linenum, line in f.ChangedContents():
1294 if 'msvs_cygwin_shell' in line:
1295 cygwin_shell.append(f.LocalPath())
1296 break
1297
1298 if cygwin_shell:
1299 return [output_api.PresubmitError(
1300 'These files should not use msvs_cygwin_shell (the default is 0):',
1301 items=cygwin_shell)]
1302 return []
1303
[email protected]85218562013-11-22 07:41:401304
[email protected]999261d2014-03-03 20:08:081305def _CheckUserActionUpdate(input_api, output_api):
1306 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521307 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081308 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521309 # If actions.xml is already included in the changelist, the PRESUBMIT
1310 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081311 return []
1312
[email protected]999261d2014-03-03 20:08:081313 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1314 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521315 current_actions = None
[email protected]999261d2014-03-03 20:08:081316 for f in input_api.AffectedFiles(file_filter=file_filter):
1317 for line_num, line in f.ChangedContents():
1318 match = input_api.re.search(action_re, line)
1319 if match:
[email protected]2f92dec2014-03-07 19:21:521320 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1321 # loaded only once.
1322 if not current_actions:
1323 with open('tools/metrics/actions/actions.xml') as actions_f:
1324 current_actions = actions_f.read()
1325 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081326 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521327 action = 'name="{0}"'.format(action_name)
1328 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081329 return [output_api.PresubmitPromptWarning(
1330 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521331 'tools/metrics/actions/actions.xml. Please run '
1332 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081333 % (f.LocalPath(), line_num, action_name))]
1334 return []
1335
1336
[email protected]99171a92014-06-03 08:44:471337def _GetJSONParseError(input_api, filename, eat_comments=True):
1338 try:
1339 contents = input_api.ReadFile(filename)
1340 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131341 import sys
1342 original_sys_path = sys.path
1343 try:
1344 sys.path = sys.path + [input_api.os_path.join(
1345 input_api.PresubmitLocalPath(),
1346 'tools', 'json_comment_eater')]
1347 import json_comment_eater
1348 finally:
1349 sys.path = original_sys_path
1350 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471351
1352 input_api.json.loads(contents)
1353 except ValueError as e:
1354 return e
1355 return None
1356
1357
1358def _GetIDLParseError(input_api, filename):
1359 try:
1360 contents = input_api.ReadFile(filename)
1361 idl_schema = input_api.os_path.join(
1362 input_api.PresubmitLocalPath(),
1363 'tools', 'json_schema_compiler', 'idl_schema.py')
1364 process = input_api.subprocess.Popen(
1365 [input_api.python_executable, idl_schema],
1366 stdin=input_api.subprocess.PIPE,
1367 stdout=input_api.subprocess.PIPE,
1368 stderr=input_api.subprocess.PIPE,
1369 universal_newlines=True)
1370 (_, error) = process.communicate(input=contents)
1371 return error or None
1372 except ValueError as e:
1373 return e
1374
1375
1376def _CheckParseErrors(input_api, output_api):
1377 """Check that IDL and JSON files do not contain syntax errors."""
1378 actions = {
1379 '.idl': _GetIDLParseError,
1380 '.json': _GetJSONParseError,
1381 }
1382 # These paths contain test data and other known invalid JSON files.
1383 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491384 r'test[\\\/]data[\\\/]',
1385 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471386 ]
1387 # Most JSON files are preprocessed and support comments, but these do not.
1388 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491389 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471390 ]
1391 # Only run IDL checker on files in these directories.
1392 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491393 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1394 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471395 ]
1396
1397 def get_action(affected_file):
1398 filename = affected_file.LocalPath()
1399 return actions.get(input_api.os_path.splitext(filename)[1])
1400
1401 def MatchesFile(patterns, path):
1402 for pattern in patterns:
1403 if input_api.re.search(pattern, path):
1404 return True
1405 return False
1406
1407 def FilterFile(affected_file):
1408 action = get_action(affected_file)
1409 if not action:
1410 return False
1411 path = affected_file.LocalPath()
1412
1413 if MatchesFile(excluded_patterns, path):
1414 return False
1415
1416 if (action == _GetIDLParseError and
1417 not MatchesFile(idl_included_patterns, path)):
1418 return False
1419 return True
1420
1421 results = []
1422 for affected_file in input_api.AffectedFiles(
1423 file_filter=FilterFile, include_deletes=False):
1424 action = get_action(affected_file)
1425 kwargs = {}
1426 if (action == _GetJSONParseError and
1427 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1428 kwargs['eat_comments'] = False
1429 parse_error = action(input_api,
1430 affected_file.AbsoluteLocalPath(),
1431 **kwargs)
1432 if parse_error:
1433 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1434 (affected_file.LocalPath(), parse_error)))
1435 return results
1436
1437
[email protected]760deea2013-12-10 19:33:491438def _CheckJavaStyle(input_api, output_api):
1439 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471440 import sys
[email protected]760deea2013-12-10 19:33:491441 original_sys_path = sys.path
1442 try:
1443 sys.path = sys.path + [input_api.os_path.join(
1444 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1445 import checkstyle
1446 finally:
1447 # Restore sys.path to what it was before.
1448 sys.path = original_sys_path
1449
1450 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091451 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511452 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491453
1454
dchenge07de812016-06-20 19:27:171455def _CheckIpcOwners(input_api, output_api):
1456 """Checks that affected files involving IPC have an IPC OWNERS rule.
1457
1458 Whether or not a file affects IPC is determined by a simple whitelist of
1459 filename patterns."""
1460 file_patterns = [
palmerb19a0932017-01-24 04:00:311461 # Legacy IPC:
dchenge07de812016-06-20 19:27:171462 '*_messages.cc',
1463 '*_messages*.h',
1464 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311465 # Mojo IPC:
dchenge07de812016-06-20 19:27:171466 '*.mojom',
1467 '*_struct_traits*.*',
1468 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311469 '*.typemap',
1470 # Android native IPC:
1471 '*.aidl',
1472 # Blink uses a different file naming convention:
1473 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171474 '*StructTraits*.*',
1475 '*TypeConverter*.*',
1476 ]
1477
scottmg7a6ed5ba2016-11-04 18:22:041478 # These third_party directories do not contain IPCs, but contain files
1479 # matching the above patterns, which trigger false positives.
1480 exclude_paths = [
1481 'third_party/crashpad/*',
1482 ]
1483
dchenge07de812016-06-20 19:27:171484 # Dictionary mapping an OWNERS file path to Patterns.
1485 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1486 # rules ) to a PatternEntry.
1487 # PatternEntry is a dictionary with two keys:
1488 # - 'files': the files that are matched by this pattern
1489 # - 'rules': the per-file rules needed for this pattern
1490 # For example, if we expect OWNERS file to contain rules for *.mojom and
1491 # *_struct_traits*.*, Patterns might look like this:
1492 # {
1493 # '*.mojom': {
1494 # 'files': ...,
1495 # 'rules': [
1496 # 'per-file *.mojom=set noparent',
1497 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1498 # ],
1499 # },
1500 # '*_struct_traits*.*': {
1501 # 'files': ...,
1502 # 'rules': [
1503 # 'per-file *_struct_traits*.*=set noparent',
1504 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1505 # ],
1506 # },
1507 # }
1508 to_check = {}
1509
1510 # Iterate through the affected files to see what we actually need to check
1511 # for. We should only nag patch authors about per-file rules if a file in that
1512 # directory would match that pattern. If a directory only contains *.mojom
1513 # files and no *_messages*.h files, we should only nag about rules for
1514 # *.mojom files.
rockot51249332016-06-23 16:32:251515 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171516 for pattern in file_patterns:
1517 if input_api.fnmatch.fnmatch(
1518 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041519 skip = False
1520 for exclude in exclude_paths:
1521 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1522 skip = True
1523 break
1524 if skip:
1525 continue
dchenge07de812016-06-20 19:27:171526 owners_file = input_api.os_path.join(
1527 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1528 if owners_file not in to_check:
1529 to_check[owners_file] = {}
1530 if pattern not in to_check[owners_file]:
1531 to_check[owners_file][pattern] = {
1532 'files': [],
1533 'rules': [
1534 'per-file %s=set noparent' % pattern,
1535 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1536 ]
1537 }
1538 to_check[owners_file][pattern]['files'].append(f)
1539 break
1540
1541 # Now go through the OWNERS files we collected, filtering out rules that are
1542 # already present in that OWNERS file.
1543 for owners_file, patterns in to_check.iteritems():
1544 try:
1545 with file(owners_file) as f:
1546 lines = set(f.read().splitlines())
1547 for entry in patterns.itervalues():
1548 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1549 ]
1550 except IOError:
1551 # No OWNERS file, so all the rules are definitely missing.
1552 continue
1553
1554 # All the remaining lines weren't found in OWNERS files, so emit an error.
1555 errors = []
1556 for owners_file, patterns in to_check.iteritems():
1557 missing_lines = []
1558 files = []
1559 for pattern, entry in patterns.iteritems():
1560 missing_lines.extend(entry['rules'])
1561 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1562 if missing_lines:
1563 errors.append(
1564 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1565 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1566
1567 results = []
1568 if errors:
vabrf5ce3bf92016-07-11 14:52:411569 if input_api.is_committing:
1570 output = output_api.PresubmitError
1571 else:
1572 output = output_api.PresubmitPromptWarning
1573 results.append(output(
dchenge07de812016-06-20 19:27:171574 'Found changes to IPC files without a security OWNER!',
1575 long_text='\n\n'.join(errors)))
1576
1577 return results
1578
1579
jbriance9e12f162016-11-25 07:57:501580def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311581 """Checks that added or removed lines in non third party affected
1582 header files do not lead to new useless class or struct forward
1583 declaration.
jbriance9e12f162016-11-25 07:57:501584 """
1585 results = []
1586 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1587 input_api.re.MULTILINE)
1588 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1589 input_api.re.MULTILINE)
1590 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311591 if (f.LocalPath().startswith('third_party') and
1592 not f.LocalPath().startswith('third_party/WebKit') and
1593 not f.LocalPath().startswith('third_party\\WebKit')):
1594 continue
1595
jbriance9e12f162016-11-25 07:57:501596 if not f.LocalPath().endswith('.h'):
1597 continue
1598
1599 contents = input_api.ReadFile(f)
1600 fwd_decls = input_api.re.findall(class_pattern, contents)
1601 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1602
1603 useless_fwd_decls = []
1604 for decl in fwd_decls:
1605 count = sum(1 for _ in input_api.re.finditer(
1606 r'\b%s\b' % input_api.re.escape(decl), contents))
1607 if count == 1:
1608 useless_fwd_decls.append(decl)
1609
1610 if not useless_fwd_decls:
1611 continue
1612
1613 for line in f.GenerateScmDiff().splitlines():
1614 if (line.startswith('-') and not line.startswith('--') or
1615 line.startswith('+') and not line.startswith('++')):
1616 for decl in useless_fwd_decls:
1617 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1618 results.append(output_api.PresubmitPromptWarning(
1619 '%s: %s forward declaration is becoming useless' %
1620 (f.LocalPath(), decl)))
1621 useless_fwd_decls.remove(decl)
1622
1623 return results
1624
1625
dskiba88634f4e2015-08-14 23:03:291626def _CheckAndroidToastUsage(input_api, output_api):
1627 """Checks that code uses org.chromium.ui.widget.Toast instead of
1628 android.widget.Toast (Chromium Toast doesn't force hardware
1629 acceleration on low-end devices, saving memory).
1630 """
1631 toast_import_pattern = input_api.re.compile(
1632 r'^import android\.widget\.Toast;$')
1633
1634 errors = []
1635
1636 sources = lambda affected_file: input_api.FilterSourceFile(
1637 affected_file,
1638 black_list=(_EXCLUDED_PATHS +
1639 _TEST_CODE_EXCLUDED_PATHS +
1640 input_api.DEFAULT_BLACK_LIST +
1641 (r'^chromecast[\\\/].*',
1642 r'^remoting[\\\/].*')),
1643 white_list=(r'.*\.java$',))
1644
1645 for f in input_api.AffectedSourceFiles(sources):
1646 for line_num, line in f.ChangedContents():
1647 if toast_import_pattern.search(line):
1648 errors.append("%s:%d" % (f.LocalPath(), line_num))
1649
1650 results = []
1651
1652 if errors:
1653 results.append(output_api.PresubmitError(
1654 'android.widget.Toast usage is detected. Android toasts use hardware'
1655 ' acceleration, and can be\ncostly on low-end devices. Please use'
1656 ' org.chromium.ui.widget.Toast instead.\n'
1657 'Contact [email protected] if you have any questions.',
1658 errors))
1659
1660 return results
1661
1662
dgnaa68d5e2015-06-10 10:08:221663def _CheckAndroidCrLogUsage(input_api, output_api):
1664 """Checks that new logs using org.chromium.base.Log:
1665 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511666 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221667 """
pkotwicza1dd0b002016-05-16 14:41:041668
1669 # Do not check format of logs in //chrome/android/webapk because
1670 # //chrome/android/webapk cannot depend on //base
1671 cr_log_check_excluded_paths = [
1672 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1673 ]
1674
dgnaa68d5e2015-06-10 10:08:221675 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121676 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1677 class_in_base_pattern = input_api.re.compile(
1678 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1679 has_some_log_import_pattern = input_api.re.compile(
1680 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221681 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121682 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221683 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511684 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221685 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221686
Vincent Scheib16d7b272015-09-15 18:09:071687 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221688 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041689 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1690 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121691
dgnaa68d5e2015-06-10 10:08:221692 tag_decl_errors = []
1693 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121694 tag_errors = []
dgn38736db2015-09-18 19:20:511695 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121696 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221697
1698 for f in input_api.AffectedSourceFiles(sources):
1699 file_content = input_api.ReadFile(f)
1700 has_modified_logs = False
1701
1702 # Per line checks
dgn87d9fb62015-06-12 09:15:121703 if (cr_log_import_pattern.search(file_content) or
1704 (class_in_base_pattern.search(file_content) and
1705 not has_some_log_import_pattern.search(file_content))):
1706 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221707 for line_num, line in f.ChangedContents():
1708
1709 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121710 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221711 if match:
1712 has_modified_logs = True
1713
1714 # Make sure it uses "TAG"
1715 if not match.group('tag') == 'TAG':
1716 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121717 else:
1718 # Report non cr Log function calls in changed lines
1719 for line_num, line in f.ChangedContents():
1720 if log_call_pattern.search(line):
1721 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221722
1723 # Per file checks
1724 if has_modified_logs:
1725 # Make sure the tag is using the "cr" prefix and is not too long
1726 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511727 tag_name = match.group('name') if match else None
1728 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221729 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511730 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221731 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511732 elif '.' in tag_name:
1733 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221734
1735 results = []
1736 if tag_decl_errors:
1737 results.append(output_api.PresubmitPromptWarning(
1738 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511739 '"private static final String TAG = "<package tag>".\n'
1740 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221741 tag_decl_errors))
1742
1743 if tag_length_errors:
1744 results.append(output_api.PresubmitError(
1745 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511746 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221747 tag_length_errors))
1748
1749 if tag_errors:
1750 results.append(output_api.PresubmitPromptWarning(
1751 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1752 tag_errors))
1753
dgn87d9fb62015-06-12 09:15:121754 if util_log_errors:
dgn4401aa52015-04-29 16:26:171755 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121756 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1757 util_log_errors))
1758
dgn38736db2015-09-18 19:20:511759 if tag_with_dot_errors:
1760 results.append(output_api.PresubmitPromptWarning(
1761 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1762 tag_with_dot_errors))
1763
dgn4401aa52015-04-29 16:26:171764 return results
1765
1766
yolandyan45001472016-12-21 21:12:421767def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1768 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1769 deprecated_annotation_import_pattern = input_api.re.compile(
1770 r'^import android\.test\.suitebuilder\.annotation\..*;',
1771 input_api.re.MULTILINE)
1772 sources = lambda x: input_api.FilterSourceFile(
1773 x, white_list=(r'.*\.java$',), black_list=None)
1774 errors = []
1775 for f in input_api.AffectedFiles(sources):
1776 for line_num, line in f.ChangedContents():
1777 if deprecated_annotation_import_pattern.search(line):
1778 errors.append("%s:%d" % (f.LocalPath(), line_num))
1779
1780 results = []
1781 if errors:
1782 results.append(output_api.PresubmitError(
1783 'Annotations in android.test.suitebuilder.annotation have been'
1784 ' deprecated since API level 24. Please use android.support.test.filters'
1785 ' from //third_party/android_support_test_runner:runner_java instead.'
1786 ' Contact [email protected] if you have any questions.', errors))
1787 return results
1788
1789
agrieve7b6479d82015-10-07 14:24:221790def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1791 """Checks if MDPI assets are placed in a correct directory."""
1792 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1793 ('/res/drawable/' in f.LocalPath() or
1794 '/res/drawable-ldrtl/' in f.LocalPath()))
1795 errors = []
1796 for f in input_api.AffectedFiles(include_deletes=False,
1797 file_filter=file_filter):
1798 errors.append(' %s' % f.LocalPath())
1799
1800 results = []
1801 if errors:
1802 results.append(output_api.PresubmitError(
1803 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1804 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1805 '/res/drawable-ldrtl/.\n'
1806 'Contact [email protected] if you have questions.', errors))
1807 return results
1808
1809
agrievef32bcc72016-04-04 14:57:401810class PydepsChecker(object):
1811 def __init__(self, input_api, pydeps_files):
1812 self._file_cache = {}
1813 self._input_api = input_api
1814 self._pydeps_files = pydeps_files
1815
1816 def _LoadFile(self, path):
1817 """Returns the list of paths within a .pydeps file relative to //."""
1818 if path not in self._file_cache:
1819 with open(path) as f:
1820 self._file_cache[path] = f.read()
1821 return self._file_cache[path]
1822
1823 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1824 """Returns an interable of paths within the .pydep, relativized to //."""
1825 os_path = self._input_api.os_path
1826 pydeps_dir = os_path.dirname(pydeps_path)
1827 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1828 if not l.startswith('*'))
1829 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1830
1831 def _CreateFilesToPydepsMap(self):
1832 """Returns a map of local_path -> list_of_pydeps."""
1833 ret = {}
1834 for pydep_local_path in self._pydeps_files:
1835 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1836 ret.setdefault(path, []).append(pydep_local_path)
1837 return ret
1838
1839 def ComputeAffectedPydeps(self):
1840 """Returns an iterable of .pydeps files that might need regenerating."""
1841 affected_pydeps = set()
1842 file_to_pydeps_map = None
1843 for f in self._input_api.AffectedFiles(include_deletes=True):
1844 local_path = f.LocalPath()
1845 if local_path == 'DEPS':
1846 return self._pydeps_files
1847 elif local_path.endswith('.pydeps'):
1848 if local_path in self._pydeps_files:
1849 affected_pydeps.add(local_path)
1850 elif local_path.endswith('.py'):
1851 if file_to_pydeps_map is None:
1852 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1853 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1854 return affected_pydeps
1855
1856 def DetermineIfStale(self, pydeps_path):
1857 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411858 import difflib
agrievef32bcc72016-04-04 14:57:401859 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1860 cmd = old_pydeps_data[1][1:].strip()
1861 new_pydeps_data = self._input_api.subprocess.check_output(
1862 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411863 old_contents = old_pydeps_data[2:]
1864 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401865 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411866 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401867
1868
1869def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1870 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001871 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281872 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1873 # Mac, so skip it on other platforms.
1874 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001875 return []
agrievef32bcc72016-04-04 14:57:401876 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1877 is_android = input_api.os_path.exists('third_party/android_tools')
1878 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1879 results = []
1880 # First, check for new / deleted .pydeps.
1881 for f in input_api.AffectedFiles(include_deletes=True):
1882 if f.LocalPath().endswith('.pydeps'):
1883 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1884 results.append(output_api.PresubmitError(
1885 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1886 'remove %s' % f.LocalPath()))
1887 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1888 results.append(output_api.PresubmitError(
1889 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1890 'include %s' % f.LocalPath()))
1891
1892 if results:
1893 return results
1894
1895 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1896
1897 for pydep_path in checker.ComputeAffectedPydeps():
1898 try:
phajdan.jr0d9878552016-11-04 10:49:411899 result = checker.DetermineIfStale(pydep_path)
1900 if result:
1901 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401902 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411903 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1904 'To regenerate, run:\n\n %s' %
1905 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401906 except input_api.subprocess.CalledProcessError as error:
1907 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1908 long_text=error.output)]
1909
1910 return results
1911
1912
glidere61efad2015-02-18 17:39:431913def _CheckSingletonInHeaders(input_api, output_api):
1914 """Checks to make sure no header files have |Singleton<|."""
1915 def FileFilter(affected_file):
1916 # It's ok for base/memory/singleton.h to have |Singleton<|.
1917 black_list = (_EXCLUDED_PATHS +
1918 input_api.DEFAULT_BLACK_LIST +
1919 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1920 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1921
sergeyu34d21222015-09-16 00:11:441922 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431923 files = []
1924 for f in input_api.AffectedSourceFiles(FileFilter):
1925 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1926 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1927 contents = input_api.ReadFile(f)
1928 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241929 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431930 pattern.search(line)):
1931 files.append(f)
1932 break
1933
1934 if files:
yolandyandaabc6d2016-04-18 18:29:391935 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441936 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431937 'Please move them to an appropriate source file so that the ' +
1938 'template gets instantiated in a single compilation unit.',
1939 files) ]
1940 return []
1941
1942
dbeam1ec68ac2016-12-15 05:22:241943def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:201944 """Checks for old style compiled_resources.gyp files."""
1945 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1946
1947 added_compiled_resources = filter(is_compiled_resource, [
1948 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1949 ])
1950
1951 if not added_compiled_resources:
1952 return []
1953
1954 return [output_api.PresubmitError(
1955 "Found new compiled_resources.gyp files:\n%s\n\n"
1956 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551957 "please use compiled_resources2.gyp instead:\n"
1958 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1959 %
dbeam37e8e7402016-02-10 22:58:201960 "\n".join(added_compiled_resources))]
1961
1962
[email protected]fd20b902014-05-09 02:14:531963_DEPRECATED_CSS = [
1964 # Values
1965 ( "-webkit-box", "flex" ),
1966 ( "-webkit-inline-box", "inline-flex" ),
1967 ( "-webkit-flex", "flex" ),
1968 ( "-webkit-inline-flex", "inline-flex" ),
1969 ( "-webkit-min-content", "min-content" ),
1970 ( "-webkit-max-content", "max-content" ),
1971
1972 # Properties
1973 ( "-webkit-background-clip", "background-clip" ),
1974 ( "-webkit-background-origin", "background-origin" ),
1975 ( "-webkit-background-size", "background-size" ),
1976 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441977 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531978
1979 # Functions
1980 ( "-webkit-gradient", "gradient" ),
1981 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1982 ( "-webkit-linear-gradient", "linear-gradient" ),
1983 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1984 ( "-webkit-radial-gradient", "radial-gradient" ),
1985 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1986]
1987
dbeam1ec68ac2016-12-15 05:22:241988def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531989 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251990 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341991 documentation and iOS CSS for dom distiller
1992 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251993 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531994 results = []
dbeam070cfe62014-10-22 06:44:021995 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251996 black_list = (_EXCLUDED_PATHS +
1997 _TEST_CODE_EXCLUDED_PATHS +
1998 input_api.DEFAULT_BLACK_LIST +
1999 (r"^chrome/common/extensions/docs",
2000 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342001 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052002 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442003 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252004 r"^native_client_sdk"))
2005 file_filter = lambda f: input_api.FilterSourceFile(
2006 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532007 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2008 for line_num, line in fpath.ChangedContents():
2009 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022010 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532011 results.append(output_api.PresubmitError(
2012 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2013 (fpath.LocalPath(), line_num, deprecated_value, value)))
2014 return results
2015
mohan.reddyf21db962014-10-16 12:26:472016
dbeam070cfe62014-10-22 06:44:022017_DEPRECATED_JS = [
2018 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2019 ( "__defineGetter__", "Object.defineProperty" ),
2020 ( "__defineSetter__", "Object.defineProperty" ),
2021]
2022
dbeam1ec68ac2016-12-15 05:22:242023def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022024 """Make sure that we don't use deprecated JS in Chrome code."""
2025 results = []
2026 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2027 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2028 input_api.DEFAULT_BLACK_LIST)
2029 file_filter = lambda f: input_api.FilterSourceFile(
2030 f, white_list=file_inclusion_pattern, black_list=black_list)
2031 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2032 for lnum, line in fpath.ChangedContents():
2033 for (deprecated, replacement) in _DEPRECATED_JS:
2034 if deprecated in line:
2035 results.append(output_api.PresubmitError(
2036 "%s:%d: Use of deprecated JS %s, use %s instead" %
2037 (fpath.LocalPath(), lnum, deprecated, replacement)))
2038 return results
2039
2040
dbeam1ec68ac2016-12-15 05:22:242041def _CheckForRiskyJsFeatures(input_api, output_api):
2042 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2043 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2044
2045 arrow_lines = []
2046 for f in input_api.AffectedFiles(file_filter=file_filter):
2047 for lnum, line in f.ChangedContents():
2048 if ' => ' in line:
2049 arrow_lines.append((f.LocalPath(), lnum))
2050
2051 if not arrow_lines:
2052 return []
2053
2054 return [output_api.PresubmitPromptWarning("""
2055Use of => operator detected in:
2056%s
2057Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2058https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2059""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2060
2061
dgnaa68d5e2015-06-10 10:08:222062def _AndroidSpecificOnUploadChecks(input_api, output_api):
2063 """Groups checks that target android code."""
2064 results = []
dgnaa68d5e2015-06-10 10:08:222065 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222066 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292067 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422068 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222069 return results
2070
2071
[email protected]22c9bd72011-03-27 16:47:392072def _CommonChecks(input_api, output_api):
2073 """Checks common to both upload and commit."""
2074 results = []
2075 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382076 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542077 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582078 results.extend(
2079 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192080 results.extend(
[email protected]760deea2013-12-10 19:33:492081 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542082 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182083 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522084 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222085 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442086 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592087 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062088 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122089 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182090 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222091 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302092 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492093 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272094 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032095 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492096 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442097 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272098 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542099 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442100 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392101 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552102 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042103 results.extend(
2104 input_api.canned_checks.CheckChangeHasNoTabs(
2105 input_api,
2106 output_api,
2107 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402108 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162109 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592110 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082111 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242112 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2113 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472114 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042115 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232116 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432117 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242118 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402119 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152120 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172121 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502122 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242123 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242124
2125 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2126 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2127 input_api, output_api,
2128 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382129 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392130 return results
[email protected]1f7b4172010-01-28 01:17:342131
[email protected]b337cb5b2011-01-23 21:24:052132
[email protected]b8079ae4a2012-12-05 19:56:492133def _CheckPatchFiles(input_api, output_api):
2134 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2135 if f.LocalPath().endswith(('.orig', '.rej'))]
2136 if problems:
2137 return [output_api.PresubmitError(
2138 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032139 else:
2140 return []
[email protected]b8079ae4a2012-12-05 19:56:492141
2142
[email protected]b00342e7f2013-03-26 16:21:542143def _DidYouMeanOSMacro(bad_macro):
2144 try:
2145 return {'A': 'OS_ANDROID',
2146 'B': 'OS_BSD',
2147 'C': 'OS_CHROMEOS',
2148 'F': 'OS_FREEBSD',
2149 'L': 'OS_LINUX',
2150 'M': 'OS_MACOSX',
2151 'N': 'OS_NACL',
2152 'O': 'OS_OPENBSD',
2153 'P': 'OS_POSIX',
2154 'S': 'OS_SOLARIS',
2155 'W': 'OS_WIN'}[bad_macro[3].upper()]
2156 except KeyError:
2157 return ''
2158
2159
2160def _CheckForInvalidOSMacrosInFile(input_api, f):
2161 """Check for sensible looking, totally invalid OS macros."""
2162 preprocessor_statement = input_api.re.compile(r'^\s*#')
2163 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2164 results = []
2165 for lnum, line in f.ChangedContents():
2166 if preprocessor_statement.search(line):
2167 for match in os_macro.finditer(line):
2168 if not match.group(1) in _VALID_OS_MACROS:
2169 good = _DidYouMeanOSMacro(match.group(1))
2170 did_you_mean = ' (did you mean %s?)' % good if good else ''
2171 results.append(' %s:%d %s%s' % (f.LocalPath(),
2172 lnum,
2173 match.group(1),
2174 did_you_mean))
2175 return results
2176
2177
2178def _CheckForInvalidOSMacros(input_api, output_api):
2179 """Check all affected files for invalid OS macros."""
2180 bad_macros = []
2181 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472182 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542183 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2184
2185 if not bad_macros:
2186 return []
2187
2188 return [output_api.PresubmitError(
2189 'Possibly invalid OS macro[s] found. Please fix your code\n'
2190 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2191
lliabraa35bab3932014-10-01 12:16:442192
2193def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2194 """Check all affected files for invalid "if defined" macros."""
2195 ALWAYS_DEFINED_MACROS = (
2196 "TARGET_CPU_PPC",
2197 "TARGET_CPU_PPC64",
2198 "TARGET_CPU_68K",
2199 "TARGET_CPU_X86",
2200 "TARGET_CPU_ARM",
2201 "TARGET_CPU_MIPS",
2202 "TARGET_CPU_SPARC",
2203 "TARGET_CPU_ALPHA",
2204 "TARGET_IPHONE_SIMULATOR",
2205 "TARGET_OS_EMBEDDED",
2206 "TARGET_OS_IPHONE",
2207 "TARGET_OS_MAC",
2208 "TARGET_OS_UNIX",
2209 "TARGET_OS_WIN32",
2210 )
2211 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2212 results = []
2213 for lnum, line in f.ChangedContents():
2214 for match in ifdef_macro.finditer(line):
2215 if match.group(1) in ALWAYS_DEFINED_MACROS:
2216 always_defined = ' %s is always defined. ' % match.group(1)
2217 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2218 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2219 lnum,
2220 always_defined,
2221 did_you_mean))
2222 return results
2223
2224
2225def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2226 """Check all affected files for invalid "if defined" macros."""
2227 bad_macros = []
2228 for f in input_api.AffectedFiles():
2229 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2230 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2231
2232 if not bad_macros:
2233 return []
2234
2235 return [output_api.PresubmitError(
2236 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2237 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2238 bad_macros)]
2239
2240
mlamouria82272622014-09-16 18:45:042241def _CheckForIPCRules(input_api, output_api):
2242 """Check for same IPC rules described in
2243 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2244 """
2245 base_pattern = r'IPC_ENUM_TRAITS\('
2246 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2247 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2248
2249 problems = []
2250 for f in input_api.AffectedSourceFiles(None):
2251 local_path = f.LocalPath()
2252 if not local_path.endswith('.h'):
2253 continue
2254 for line_number, line in f.ChangedContents():
2255 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2256 problems.append(
2257 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2258
2259 if problems:
2260 return [output_api.PresubmitPromptWarning(
2261 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2262 else:
2263 return []
2264
[email protected]b00342e7f2013-03-26 16:21:542265
mostynbb639aca52015-01-07 20:31:232266def _CheckForWindowsLineEndings(input_api, output_api):
2267 """Check source code and known ascii text files for Windows style line
2268 endings.
2269 """
earthdok1b5e0ee2015-03-10 15:19:102270 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232271
2272 file_inclusion_pattern = (
2273 known_text_files,
2274 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2275 )
2276
2277 filter = lambda f: input_api.FilterSourceFile(
2278 f, white_list=file_inclusion_pattern, black_list=None)
2279 files = [f.LocalPath() for f in
2280 input_api.AffectedSourceFiles(filter)]
2281
2282 problems = []
2283
2284 for file in files:
2285 fp = open(file, 'r')
2286 for line in fp:
2287 if line.endswith('\r\n'):
2288 problems.append(file)
2289 break
2290 fp.close()
2291
2292 if problems:
2293 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2294 'these files to contain Windows style line endings?\n' +
2295 '\n'.join(problems))]
2296
2297 return []
2298
2299
pastarmovj89f7ee12016-09-20 14:58:132300def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2301 lint_filters=None, verbose_level=None):
2302 """Checks that all source files use SYSLOG properly."""
2303 syslog_files = []
2304 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562305 for line_number, line in f.ChangedContents():
2306 if 'SYSLOG' in line:
2307 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2308
pastarmovj89f7ee12016-09-20 14:58:132309 if syslog_files:
2310 return [output_api.PresubmitPromptWarning(
2311 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2312 ' calls.\nFiles to check:\n', items=syslog_files)]
2313 return []
2314
2315
[email protected]1f7b4172010-01-28 01:17:342316def CheckChangeOnUpload(input_api, output_api):
2317 results = []
2318 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472319 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282320 results.extend(
jam93a6ee792017-02-08 23:59:222321 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
2322 results.extend(
scottmg39b29952014-12-08 18:31:282323 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192324 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222325 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132326 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162327 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542328 return results
[email protected]ca8d1982009-02-19 16:33:122329
2330
[email protected]1bfb8322014-04-23 01:02:412331def GetTryServerMasterForBot(bot):
2332 """Returns the Try Server master for the given bot.
2333
[email protected]0bb112362014-07-26 04:38:322334 It tries to guess the master from the bot name, but may still fail
2335 and return None. There is no longer a default master.
2336 """
2337 # Potentially ambiguous bot names are listed explicitly.
2338 master_map = {
tandriie5587792016-07-14 00:34:502339 'chromium_presubmit': 'master.tryserver.chromium.linux',
2340 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412341 }
[email protected]0bb112362014-07-26 04:38:322342 master = master_map.get(bot)
2343 if not master:
wnwen4fbaab82016-05-25 12:54:362344 if 'android' in bot:
tandriie5587792016-07-14 00:34:502345 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362346 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502347 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322348 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502349 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322350 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502351 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322352 return master
[email protected]1bfb8322014-04-23 01:02:412353
2354
Paweł Hajdan, Jr55083782014-12-19 20:32:562355def GetDefaultTryConfigs(bots):
2356 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012357 """
2358
Paweł Hajdan, Jr55083782014-12-19 20:32:562359 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412360
2361 # Build up the mapping from tryserver master to bot/test.
2362 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562363 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412364 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2365 return out
[email protected]38c6a512013-12-18 23:48:012366
2367
[email protected]ca8d1982009-02-19 16:33:122368def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542369 results = []
[email protected]1f7b4172010-01-28 01:17:342370 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542371 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272372 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342373 input_api,
2374 output_api,
[email protected]2fdd1f362013-01-16 03:56:032375 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272376
jam93a6ee792017-02-08 23:59:222377 results.extend(
2378 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542379 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2380 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412381 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2382 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542383 return results