blob: 2284a0f5d46ae3d8251ab9250989466623bf0c6e [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
[email protected]4306417642009-06-11 00:33:4028)
[email protected]ca8d19842009-02-19 16:33:1229
wnwenbdc444e2016-05-25 13:44:1530
[email protected]06e6d0ff2012-12-11 01:36:4431# Fragment of a regular expression that matches C++ and Objective-C++
32# implementation files.
33_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
34
wnwenbdc444e2016-05-25 13:44:1535
[email protected]06e6d0ff2012-12-11 01:36:4436# Regular expression that matches code only used for test binaries
37# (best effort).
38_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4939 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4440 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5341 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1242 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4944 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0545 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4946 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4747 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4948 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0849 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4950 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4451)
[email protected]ca8d19842009-02-19 16:33:1252
wnwenbdc444e2016-05-25 13:44:1553
[email protected]eea609a2011-11-18 13:10:1254_TEST_ONLY_WARNING = (
55 'You might be calling functions intended only for testing from\n'
56 'production code. It is OK to ignore this warning if you know what\n'
57 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5858 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1259
60
[email protected]cf9b78f2012-11-14 11:40:2861_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4062 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2163 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
64 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2865
wnwenbdc444e2016-05-25 13:44:1566
[email protected]127f18ec2012-06-16 05:05:5967_BANNED_OBJC_FUNCTIONS = (
68 (
69 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2070 (
71 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5972 'prohibited. Please use CrTrackingArea instead.',
73 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
74 ),
75 False,
76 ),
77 (
[email protected]eaae1972014-04-16 04:17:2678 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2079 (
80 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5981 'instead.',
82 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
83 ),
84 False,
85 ),
86 (
87 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2088 (
89 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5990 'Please use |convertPoint:(point) fromView:nil| instead.',
91 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
92 ),
93 True,
94 ),
95 (
96 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5999 'Please use |convertPoint:(point) toView:nil| instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 True,
103 ),
104 (
105 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59108 'Please use |convertRect:(point) fromView:nil| instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 True,
112 ),
113 (
114 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertRect:(point) toView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertSize:(point) fromView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertSize:(point) toView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
jif65398702016-10-27 10:19:48140 (
141 r"/\s+UTF8String\s*]",
142 (
143 'The use of -[NSString UTF8String] is dangerous as it can return null',
144 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
145 'Please use |SysNSStringToUTF8| instead.',
146 ),
147 True,
148 ),
[email protected]127f18ec2012-06-16 05:05:59149)
150
151
152_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20153 # Make sure that gtest's FRIEND_TEST() macro is not used; the
154 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30155 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20156 (
157 'FRIEND_TEST(',
158 (
[email protected]e3c945502012-06-26 20:01:49159 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20160 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
161 ),
162 False,
[email protected]7345da02012-11-27 14:31:49163 (),
[email protected]23e6cbc2012-06-16 18:51:20164 ),
165 (
thomasanderson4b569052016-09-14 20:15:53166 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
167 (
168 'Chrome clients wishing to select events on X windows should use',
169 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
170 'you are selecting events from the GPU process, or if you are using',
171 'an XDisplay other than gfx::GetXDisplay().',
172 ),
173 True,
174 (
175 r"^ui[\\\/]gl[\\\/].*\.cc$",
176 r"^media[\\\/]gpu[\\\/].*\.cc$",
177 r"^gpu[\\\/].*\.cc$",
178 ),
179 ),
180 (
[email protected]23e6cbc2012-06-16 18:51:20181 'ScopedAllowIO',
182 (
[email protected]e3c945502012-06-26 20:01:49183 'New code should not use ScopedAllowIO. Post a task to the blocking',
184 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20185 ),
[email protected]e3c945502012-06-26 20:01:49186 True,
[email protected]7345da02012-11-27 14:31:49187 (
nyad2c548b2015-12-09 03:22:32188 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10189 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49190 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22191 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31192 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51193 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
194 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09195 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49196 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
197 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25198 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41199 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
200 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25201 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48202 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
203 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01204 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25205 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
206 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
207 r"embedded_test_server\.cc$",
208 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
209 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54210 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16211 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53212 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
213 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45214 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
215 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
216 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
217 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
218 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49219 ),
[email protected]23e6cbc2012-06-16 18:51:20220 ),
[email protected]52657f62013-05-20 05:30:31221 (
tomhudsone2c14d552016-05-26 17:07:46222 'setMatrixClip',
223 (
224 'Overriding setMatrixClip() is prohibited; ',
225 'the base function is deprecated. ',
226 ),
227 True,
228 (),
229 ),
230 (
[email protected]52657f62013-05-20 05:30:31231 'SkRefPtr',
232 (
233 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22234 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31235 ),
236 True,
237 (),
238 ),
239 (
240 'SkAutoRef',
241 (
242 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22243 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31244 ),
245 True,
246 (),
247 ),
248 (
249 'SkAutoTUnref',
250 (
251 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22252 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31253 ),
254 True,
255 (),
256 ),
257 (
258 'SkAutoUnref',
259 (
260 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
261 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22262 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31263 ),
264 True,
265 (),
266 ),
[email protected]d89eec82013-12-03 14:10:59267 (
268 r'/HANDLE_EINTR\(.*close',
269 (
270 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
271 'descriptor will be closed, and it is incorrect to retry the close.',
272 'Either call close directly and ignore its return value, or wrap close',
273 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
274 ),
275 True,
276 (),
277 ),
278 (
279 r'/IGNORE_EINTR\((?!.*close)',
280 (
281 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
282 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
283 ),
284 True,
285 (
286 # Files that #define IGNORE_EINTR.
287 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
288 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
289 ),
290 ),
[email protected]ec5b3f02014-04-04 18:43:43291 (
292 r'/v8::Extension\(',
293 (
294 'Do not introduce new v8::Extensions into the code base, use',
295 'gin::Wrappable instead. See http://crbug.com/334679',
296 ),
297 True,
[email protected]f55c90ee62014-04-12 00:50:03298 (
joaodasilva718f87672014-08-30 09:25:49299 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03300 ),
[email protected]ec5b3f02014-04-04 18:43:43301 ),
skyostilf9469f72015-04-20 10:38:52302 (
jame2d1a952016-04-02 00:27:10303 '#pragma comment(lib,',
304 (
305 'Specify libraries to link with in build files and not in the source.',
306 ),
307 True,
308 (),
309 ),
[email protected]127f18ec2012-06-16 05:05:59310)
311
wnwenbdc444e2016-05-25 13:44:15312
mlamouria82272622014-09-16 18:45:04313_IPC_ENUM_TRAITS_DEPRECATED = (
314 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
315 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
316
[email protected]127f18ec2012-06-16 05:05:59317
[email protected]b00342e7f2013-03-26 16:21:54318_VALID_OS_MACROS = (
319 # Please keep sorted.
320 'OS_ANDROID',
321 'OS_BSD',
322 'OS_CAT', # For testing.
323 'OS_CHROMEOS',
324 'OS_FREEBSD',
325 'OS_IOS',
326 'OS_LINUX',
327 'OS_MACOSX',
328 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21329 'OS_NACL_NONSFI',
330 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12331 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54332 'OS_OPENBSD',
333 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37334 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54335 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54336 'OS_WIN',
337)
338
339
agrievef32bcc72016-04-04 14:57:40340_ANDROID_SPECIFIC_PYDEPS_FILES = [
341 'build/android/test_runner.pydeps',
agrieve732db3a2016-04-26 19:18:19342 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40343]
344
wnwenbdc444e2016-05-25 13:44:15345
agrievef32bcc72016-04-04 14:57:40346_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40347]
348
wnwenbdc444e2016-05-25 13:44:15349
agrievef32bcc72016-04-04 14:57:40350_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
351
352
[email protected]55459852011-08-10 15:17:19353def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
354 """Attempts to prevent use of functions intended only for testing in
355 non-testing code. For now this is just a best-effort implementation
356 that ignores header files and may have some false positives. A
357 better implementation would probably need a proper C++ parser.
358 """
359 # We only scan .cc files and the like, as the declaration of
360 # for-testing functions in header files are hard to distinguish from
361 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44362 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19363
jochenc0d4808c2015-07-27 09:25:42364 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19365 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09366 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19367 exclusion_pattern = input_api.re.compile(
368 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
369 base_function_pattern, base_function_pattern))
370
371 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44372 black_list = (_EXCLUDED_PATHS +
373 _TEST_CODE_EXCLUDED_PATHS +
374 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19375 return input_api.FilterSourceFile(
376 affected_file,
377 white_list=(file_inclusion_pattern, ),
378 black_list=black_list)
379
380 problems = []
381 for f in input_api.AffectedSourceFiles(FilterFile):
382 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24383 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03384 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46385 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03386 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19387 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03388 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19389
390 if problems:
[email protected]f7051d52013-04-02 18:31:42391 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03392 else:
393 return []
[email protected]55459852011-08-10 15:17:19394
395
[email protected]10689ca2011-09-02 02:31:54396def _CheckNoIOStreamInHeaders(input_api, output_api):
397 """Checks to make sure no .h files include <iostream>."""
398 files = []
399 pattern = input_api.re.compile(r'^#include\s*<iostream>',
400 input_api.re.MULTILINE)
401 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
402 if not f.LocalPath().endswith('.h'):
403 continue
404 contents = input_api.ReadFile(f)
405 if pattern.search(contents):
406 files.append(f)
407
408 if len(files):
yolandyandaabc6d2016-04-18 18:29:39409 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06410 'Do not #include <iostream> in header files, since it inserts static '
411 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54412 '#include <ostream>. See http://crbug.com/94794',
413 files) ]
414 return []
415
416
[email protected]72df4e782012-06-21 16:28:18417def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52418 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18419 problems = []
420 for f in input_api.AffectedFiles():
421 if (not f.LocalPath().endswith(('.cc', '.mm'))):
422 continue
423
424 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04425 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18426 problems.append(' %s:%d' % (f.LocalPath(), line_num))
427
428 if not problems:
429 return []
430 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
431 '\n'.join(problems))]
432
433
danakj61c1aa22015-10-26 19:55:52434def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
435 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
436 errors = []
437 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
438 input_api.re.MULTILINE)
439 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
440 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
441 continue
442 for lnum, line in f.ChangedContents():
443 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17444 errors.append(output_api.PresubmitError(
445 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
446 'DCHECK_IS_ON()", not forgetting the braces.')
447 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52448 return errors
449
450
mcasasb7440c282015-02-04 14:52:19451def _FindHistogramNameInLine(histogram_name, line):
452 """Tries to find a histogram name or prefix in a line."""
453 if not "affected-histogram" in line:
454 return histogram_name in line
455 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
456 # the histogram_name.
457 if not '"' in line:
458 return False
459 histogram_prefix = line.split('\"')[1]
460 return histogram_prefix in histogram_name
461
462
463def _CheckUmaHistogramChanges(input_api, output_api):
464 """Check that UMA histogram names in touched lines can still be found in other
465 lines of the patch or in histograms.xml. Note that this check would not catch
466 the reverse: changes in histograms.xml not matched in the code itself."""
467 touched_histograms = []
468 histograms_xml_modifications = []
469 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
470 for f in input_api.AffectedFiles():
471 # If histograms.xml itself is modified, keep the modified lines for later.
472 if f.LocalPath().endswith(('histograms.xml')):
473 histograms_xml_modifications = f.ChangedContents()
474 continue
475 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
476 continue
477 for line_num, line in f.ChangedContents():
478 found = pattern.search(line)
479 if found:
480 touched_histograms.append([found.group(1), f, line_num])
481
482 # Search for the touched histogram names in the local modifications to
483 # histograms.xml, and, if not found, on the base histograms.xml file.
484 unmatched_histograms = []
485 for histogram_info in touched_histograms:
486 histogram_name_found = False
487 for line_num, line in histograms_xml_modifications:
488 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
489 if histogram_name_found:
490 break
491 if not histogram_name_found:
492 unmatched_histograms.append(histogram_info)
493
eromanb90c82e7e32015-04-01 15:13:49494 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19495 problems = []
496 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49497 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19498 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45499 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19500 histogram_name_found = False
501 for line in histograms_xml:
502 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
503 if histogram_name_found:
504 break
505 if not histogram_name_found:
506 problems.append(' [%s:%d] %s' %
507 (f.LocalPath(), line_num, histogram_name))
508
509 if not problems:
510 return []
511 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
512 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49513 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19514
wnwenbdc444e2016-05-25 13:44:15515
yolandyandaabc6d2016-04-18 18:29:39516def _CheckFlakyTestUsage(input_api, output_api):
517 """Check that FlakyTest annotation is our own instead of the android one"""
518 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
519 files = []
520 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
521 if f.LocalPath().endswith('Test.java'):
522 if pattern.search(input_api.ReadFile(f)):
523 files.append(f)
524 if len(files):
525 return [output_api.PresubmitError(
526 'Use org.chromium.base.test.util.FlakyTest instead of '
527 'android.test.FlakyTest',
528 files)]
529 return []
mcasasb7440c282015-02-04 14:52:19530
wnwenbdc444e2016-05-25 13:44:15531
[email protected]8ea5d4b2011-09-13 21:49:22532def _CheckNoNewWStrings(input_api, output_api):
533 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27534 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22535 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20536 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57537 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34538 '/win/' in f.LocalPath() or
539 'chrome_elf' in f.LocalPath() or
540 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20541 continue
[email protected]8ea5d4b2011-09-13 21:49:22542
[email protected]a11dbe9b2012-08-07 01:32:58543 allowWString = False
[email protected]b5c24292011-11-28 14:38:20544 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58545 if 'presubmit: allow wstring' in line:
546 allowWString = True
547 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27548 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58549 allowWString = False
550 else:
551 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22552
[email protected]55463aa62011-10-12 00:48:27553 if not problems:
554 return []
555 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58556 ' If you are calling a cross-platform API that accepts a wstring, '
557 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27558 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22559
560
[email protected]2a8ac9c2011-10-19 17:20:44561def _CheckNoDEPSGIT(input_api, output_api):
562 """Make sure .DEPS.git is never modified manually."""
563 if any(f.LocalPath().endswith('.DEPS.git') for f in
564 input_api.AffectedFiles()):
565 return [output_api.PresubmitError(
566 'Never commit changes to .DEPS.git. This file is maintained by an\n'
567 'automated system based on what\'s in DEPS and your changes will be\n'
568 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34569 '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:44570 'for more information')]
571 return []
572
573
tandriief664692014-09-23 14:51:47574def _CheckValidHostsInDEPS(input_api, output_api):
575 """Checks that DEPS file deps are from allowed_hosts."""
576 # Run only if DEPS file has been modified to annoy fewer bystanders.
577 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
578 return []
579 # Outsource work to gclient verify
580 try:
581 input_api.subprocess.check_output(['gclient', 'verify'])
582 return []
583 except input_api.subprocess.CalledProcessError, error:
584 return [output_api.PresubmitError(
585 'DEPS file must have only git dependencies.',
586 long_text=error.output)]
587
588
[email protected]127f18ec2012-06-16 05:05:59589def _CheckNoBannedFunctions(input_api, output_api):
590 """Make sure that banned functions are not used."""
591 warnings = []
592 errors = []
593
wnwenbdc444e2016-05-25 13:44:15594 def IsBlacklisted(affected_file, blacklist):
595 local_path = affected_file.LocalPath()
596 for item in blacklist:
597 if input_api.re.match(item, local_path):
598 return True
599 return False
600
601 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
602 matched = False
603 if func_name[0:1] == '/':
604 regex = func_name[1:]
605 if input_api.re.search(regex, line):
606 matched = True
607 elif func_name in line:
dchenge07de812016-06-20 19:27:17608 matched = True
wnwenbdc444e2016-05-25 13:44:15609 if matched:
dchenge07de812016-06-20 19:27:17610 problems = warnings
wnwenbdc444e2016-05-25 13:44:15611 if error:
dchenge07de812016-06-20 19:27:17612 problems = errors
wnwenbdc444e2016-05-25 13:44:15613 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
614 for message_line in message:
615 problems.append(' %s' % message_line)
616
[email protected]127f18ec2012-06-16 05:05:59617 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
618 for f in input_api.AffectedFiles(file_filter=file_filter):
619 for line_num, line in f.ChangedContents():
620 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15621 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59622
623 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
624 for f in input_api.AffectedFiles(file_filter=file_filter):
625 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49626 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49627 if IsBlacklisted(f, excluded_paths):
628 continue
wnwenbdc444e2016-05-25 13:44:15629 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59630
631 result = []
632 if (warnings):
633 result.append(output_api.PresubmitPromptWarning(
634 'Banned functions were used.\n' + '\n'.join(warnings)))
635 if (errors):
636 result.append(output_api.PresubmitError(
637 'Banned functions were used.\n' + '\n'.join(errors)))
638 return result
639
640
[email protected]6c063c62012-07-11 19:11:06641def _CheckNoPragmaOnce(input_api, output_api):
642 """Make sure that banned functions are not used."""
643 files = []
644 pattern = input_api.re.compile(r'^#pragma\s+once',
645 input_api.re.MULTILINE)
646 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
647 if not f.LocalPath().endswith('.h'):
648 continue
649 contents = input_api.ReadFile(f)
650 if pattern.search(contents):
651 files.append(f)
652
653 if files:
654 return [output_api.PresubmitError(
655 'Do not use #pragma once in header files.\n'
656 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
657 files)]
658 return []
659
[email protected]127f18ec2012-06-16 05:05:59660
[email protected]e7479052012-09-19 00:26:12661def _CheckNoTrinaryTrueFalse(input_api, output_api):
662 """Checks to make sure we don't introduce use of foo ? true : false."""
663 problems = []
664 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
665 for f in input_api.AffectedFiles():
666 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
667 continue
668
669 for line_num, line in f.ChangedContents():
670 if pattern.match(line):
671 problems.append(' %s:%d' % (f.LocalPath(), line_num))
672
673 if not problems:
674 return []
675 return [output_api.PresubmitPromptWarning(
676 'Please consider avoiding the "? true : false" pattern if possible.\n' +
677 '\n'.join(problems))]
678
679
[email protected]55f9f382012-07-31 11:02:18680def _CheckUnwantedDependencies(input_api, output_api):
681 """Runs checkdeps on #include statements added in this
682 change. Breaking - rules is an error, breaking ! rules is a
683 warning.
684 """
mohan.reddyf21db962014-10-16 12:26:47685 import sys
[email protected]55f9f382012-07-31 11:02:18686 # We need to wait until we have an input_api object and use this
687 # roundabout construct to import checkdeps because this file is
688 # eval-ed and thus doesn't have __file__.
689 original_sys_path = sys.path
690 try:
691 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47692 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18693 import checkdeps
694 from cpp_checker import CppChecker
695 from rules import Rule
696 finally:
697 # Restore sys.path to what it was before.
698 sys.path = original_sys_path
699
700 added_includes = []
701 for f in input_api.AffectedFiles():
702 if not CppChecker.IsCppFile(f.LocalPath()):
703 continue
704
705 changed_lines = [line for line_num, line in f.ChangedContents()]
706 added_includes.append([f.LocalPath(), changed_lines])
707
[email protected]26385172013-05-09 23:11:35708 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18709
710 error_descriptions = []
711 warning_descriptions = []
712 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
713 added_includes):
714 description_with_path = '%s\n %s' % (path, rule_description)
715 if rule_type == Rule.DISALLOW:
716 error_descriptions.append(description_with_path)
717 else:
718 warning_descriptions.append(description_with_path)
719
720 results = []
721 if error_descriptions:
722 results.append(output_api.PresubmitError(
723 'You added one or more #includes that violate checkdeps rules.',
724 error_descriptions))
725 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42726 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18727 'You added one or more #includes of files that are temporarily\n'
728 'allowed but being removed. Can you avoid introducing the\n'
729 '#include? See relevant DEPS file(s) for details and contacts.',
730 warning_descriptions))
731 return results
732
733
[email protected]fbcafe5a2012-08-08 15:31:22734def _CheckFilePermissions(input_api, output_api):
735 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15736 if input_api.platform == 'win32':
737 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29738 checkperms_tool = input_api.os_path.join(
739 input_api.PresubmitLocalPath(),
740 'tools', 'checkperms', 'checkperms.py')
741 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47742 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22743 for f in input_api.AffectedFiles():
744 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11745 try:
746 input_api.subprocess.check_output(args)
747 return []
748 except input_api.subprocess.CalledProcessError as error:
749 return [output_api.PresubmitError(
750 'checkperms.py failed:',
751 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22752
753
robertocn832f5992017-01-04 19:01:30754def _CheckTeamTags(input_api, output_api):
755 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
756 checkteamtags_tool = input_api.os_path.join(
757 input_api.PresubmitLocalPath(),
758 'tools', 'checkteamtags', 'checkteamtags.py')
759 args = [input_api.python_executable, checkteamtags_tool,
760 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22761 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30762 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
763 'OWNERS']
764 try:
765 if files:
766 input_api.subprocess.check_output(args + files)
767 return []
768 except input_api.subprocess.CalledProcessError as error:
769 return [output_api.PresubmitError(
770 'checkteamtags.py failed:',
771 long_text=error.output)]
772
773
[email protected]c8278b32012-10-30 20:35:49774def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
775 """Makes sure we don't include ui/aura/window_property.h
776 in header files.
777 """
778 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
779 errors = []
780 for f in input_api.AffectedFiles():
781 if not f.LocalPath().endswith('.h'):
782 continue
783 for line_num, line in f.ChangedContents():
784 if pattern.match(line):
785 errors.append(' %s:%d' % (f.LocalPath(), line_num))
786
787 results = []
788 if errors:
789 results.append(output_api.PresubmitError(
790 'Header files should not include ui/aura/window_property.h', errors))
791 return results
792
793
[email protected]cf9b78f2012-11-14 11:40:28794def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
795 """Checks that the lines in scope occur in the right order.
796
797 1. C system files in alphabetical order
798 2. C++ system files in alphabetical order
799 3. Project's .h files
800 """
801
802 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
803 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
804 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
805
806 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
807
808 state = C_SYSTEM_INCLUDES
809
810 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57811 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28812 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55813 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28814 for line_num, line in scope:
815 if c_system_include_pattern.match(line):
816 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55817 problem_linenums.append((line_num, previous_line_num,
818 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28819 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55820 problem_linenums.append((line_num, previous_line_num,
821 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28822 elif cpp_system_include_pattern.match(line):
823 if state == C_SYSTEM_INCLUDES:
824 state = CPP_SYSTEM_INCLUDES
825 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55826 problem_linenums.append((line_num, previous_line_num,
827 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28828 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55829 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28830 elif custom_include_pattern.match(line):
831 if state != CUSTOM_INCLUDES:
832 state = CUSTOM_INCLUDES
833 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55834 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28835 else:
brucedawson70fadb02015-06-30 17:47:55836 problem_linenums.append((line_num, previous_line_num,
837 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28838 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57839 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28840
841 warnings = []
brucedawson70fadb02015-06-30 17:47:55842 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57843 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55844 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28845 return warnings
846
847
[email protected]ac294a12012-12-06 16:38:43848def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28849 """Checks the #include order for the given file f."""
850
[email protected]2299dcf2012-11-15 19:56:24851 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30852 # Exclude the following includes from the check:
853 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
854 # specific order.
855 # 2) <atlbase.h>, "build/build_config.h"
856 excluded_include_pattern = input_api.re.compile(
857 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24858 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33859 # Match the final or penultimate token if it is xxxtest so we can ignore it
860 # when considering the special first include.
861 test_file_tag_pattern = input_api.re.compile(
862 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11863 if_pattern = input_api.re.compile(
864 r'\s*#\s*(if|elif|else|endif|define|undef).*')
865 # Some files need specialized order of includes; exclude such files from this
866 # check.
867 uncheckable_includes_pattern = input_api.re.compile(
868 r'\s*#include '
869 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28870
871 contents = f.NewContents()
872 warnings = []
873 line_num = 0
874
[email protected]ac294a12012-12-06 16:38:43875 # Handle the special first include. If the first include file is
876 # some/path/file.h, the corresponding including file can be some/path/file.cc,
877 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
878 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33879 # If the included file is some/path/file_platform.h the including file could
880 # also be some/path/file_xxxtest_platform.h.
881 including_file_base_name = test_file_tag_pattern.sub(
882 '', input_api.os_path.basename(f.LocalPath()))
883
[email protected]ac294a12012-12-06 16:38:43884 for line in contents:
885 line_num += 1
886 if system_include_pattern.match(line):
887 # No special first include -> process the line again along with normal
888 # includes.
889 line_num -= 1
890 break
891 match = custom_include_pattern.match(line)
892 if match:
893 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33894 header_basename = test_file_tag_pattern.sub(
895 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
896
897 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24898 # No special first include -> process the line again along with normal
899 # includes.
900 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43901 break
[email protected]cf9b78f2012-11-14 11:40:28902
903 # Split into scopes: Each region between #if and #endif is its own scope.
904 scopes = []
905 current_scope = []
906 for line in contents[line_num:]:
907 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11908 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54909 continue
[email protected]2309b0fa02012-11-16 12:18:27910 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28911 scopes.append(current_scope)
912 current_scope = []
[email protected]962f117e2012-11-22 18:11:56913 elif ((system_include_pattern.match(line) or
914 custom_include_pattern.match(line)) and
915 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28916 current_scope.append((line_num, line))
917 scopes.append(current_scope)
918
919 for scope in scopes:
920 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
921 changed_linenums))
922 return warnings
923
924
925def _CheckIncludeOrder(input_api, output_api):
926 """Checks that the #include order is correct.
927
928 1. The corresponding header for source files.
929 2. C system files in alphabetical order
930 3. C++ system files in alphabetical order
931 4. Project's .h files in alphabetical order
932
[email protected]ac294a12012-12-06 16:38:43933 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
934 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28935 """
[email protected]e120b012014-08-15 19:08:35936 def FileFilterIncludeOrder(affected_file):
937 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
938 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28939
940 warnings = []
[email protected]e120b012014-08-15 19:08:35941 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08942 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43943 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
944 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28945
946 results = []
947 if warnings:
[email protected]f7051d52013-04-02 18:31:42948 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53949 warnings))
[email protected]cf9b78f2012-11-14 11:40:28950 return results
951
952
[email protected]70ca77752012-11-20 03:45:03953def _CheckForVersionControlConflictsInFile(input_api, f):
954 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
955 errors = []
956 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23957 if f.LocalPath().endswith('.md'):
958 # First-level headers in markdown look a lot like version control
959 # conflict markers. http://daringfireball.net/projects/markdown/basics
960 continue
[email protected]70ca77752012-11-20 03:45:03961 if pattern.match(line):
962 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
963 return errors
964
965
966def _CheckForVersionControlConflicts(input_api, output_api):
967 """Usually this is not intentional and will cause a compile failure."""
968 errors = []
969 for f in input_api.AffectedFiles():
970 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
971
972 results = []
973 if errors:
974 results.append(output_api.PresubmitError(
975 'Version control conflict markers found, please resolve.', errors))
976 return results
977
978
[email protected]06e6d0ff2012-12-11 01:36:44979def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
980 def FilterFile(affected_file):
981 """Filter function for use with input_api.AffectedSourceFiles,
982 below. This filters out everything except non-test files from
983 top-level directories that generally speaking should not hard-code
984 service URLs (e.g. src/android_webview/, src/content/ and others).
985 """
986 return input_api.FilterSourceFile(
987 affected_file,
[email protected]78bb39d62012-12-11 15:11:56988 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44989 black_list=(_EXCLUDED_PATHS +
990 _TEST_CODE_EXCLUDED_PATHS +
991 input_api.DEFAULT_BLACK_LIST))
992
reillyi38965732015-11-16 18:27:33993 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
994 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46995 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
996 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44997 problems = [] # items are (filename, line_number, line)
998 for f in input_api.AffectedSourceFiles(FilterFile):
999 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461000 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441001 problems.append((f.LocalPath(), line_num, line))
1002
1003 if problems:
[email protected]f7051d52013-04-02 18:31:421004 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441005 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581006 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441007 [' %s:%d: %s' % (
1008 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031009 else:
1010 return []
[email protected]06e6d0ff2012-12-11 01:36:441011
1012
[email protected]d2530012013-01-25 16:39:271013def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1014 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311015 The native_client_sdk directory is excluded because it has auto-generated PNG
1016 files for documentation.
[email protected]d2530012013-01-25 16:39:271017 """
[email protected]d2530012013-01-25 16:39:271018 errors = []
binji0dcdf342014-12-12 18:32:311019 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1020 black_list = (r'^native_client_sdk[\\\/]',)
1021 file_filter = lambda f: input_api.FilterSourceFile(
1022 f, white_list=white_list, black_list=black_list)
1023 for f in input_api.AffectedFiles(include_deletes=False,
1024 file_filter=file_filter):
1025 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271026
1027 results = []
1028 if errors:
1029 results.append(output_api.PresubmitError(
1030 'The name of PNG files should not have abbreviations. \n'
1031 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1032 'Contact [email protected] if you have questions.', errors))
1033 return results
1034
1035
[email protected]14a6131c2014-01-08 01:15:411036def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:081037 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411038 a set of DEPS entries that we should look up.
1039
1040 For a directory (rather than a specific filename) we fake a path to
1041 a specific filename by adding /DEPS. This is chosen as a file that
1042 will seldom or never be subject to per-file include_rules.
1043 """
[email protected]2b438d62013-11-14 17:54:141044 # We ignore deps entries on auto-generated directories.
1045 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081046
1047 # This pattern grabs the path without basename in the first
1048 # parentheses, and the basename (if present) in the second. It
1049 # relies on the simple heuristic that if there is a basename it will
1050 # be a header file ending in ".h".
1051 pattern = re.compile(
1052 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141053 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081054 for changed_line in changed_lines:
1055 m = pattern.match(changed_line)
1056 if m:
1057 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141058 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411059 if m.group(2):
1060 results.add('%s%s' % (path, m.group(2)))
1061 else:
1062 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081063 return results
1064
1065
[email protected]e871964c2013-05-13 14:14:551066def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1067 """When a dependency prefixed with + is added to a DEPS file, we
1068 want to make sure that the change is reviewed by an OWNER of the
1069 target file or directory, to avoid layering violations from being
1070 introduced. This check verifies that this happens.
1071 """
1072 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241073
1074 file_filter = lambda f: not input_api.re.match(
1075 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1076 for f in input_api.AffectedFiles(include_deletes=False,
1077 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551078 filename = input_api.os_path.basename(f.LocalPath())
1079 if filename == 'DEPS':
1080 changed_lines |= set(line.strip()
1081 for line_num, line
1082 in f.ChangedContents())
1083 if not changed_lines:
1084 return []
1085
[email protected]14a6131c2014-01-08 01:15:411086 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1087 changed_lines)
[email protected]e871964c2013-05-13 14:14:551088 if not virtual_depended_on_files:
1089 return []
1090
1091 if input_api.is_committing:
1092 if input_api.tbr:
1093 return [output_api.PresubmitNotifyResult(
1094 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271095 if input_api.dry_run:
1096 return [output_api.PresubmitNotifyResult(
1097 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551098 if not input_api.change.issue:
1099 return [output_api.PresubmitError(
1100 "DEPS approval by OWNERS check failed: this change has "
1101 "no Rietveld issue number, so we can't check it for approvals.")]
1102 output = output_api.PresubmitError
1103 else:
1104 output = output_api.PresubmitNotifyResult
1105
1106 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501107 owner_email, reviewers = (
1108 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1109 input_api,
1110 owners_db.email_regexp,
1111 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551112
1113 owner_email = owner_email or input_api.change.author_email
1114
[email protected]de4f7d22013-05-23 14:27:461115 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511116 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461117 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551118 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1119 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411120
1121 # We strip the /DEPS part that was added by
1122 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1123 # directory.
1124 def StripDeps(path):
1125 start_deps = path.rfind('/DEPS')
1126 if start_deps != -1:
1127 return path[:start_deps]
1128 else:
1129 return path
1130 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551131 for path in missing_files]
1132
1133 if unapproved_dependencies:
1134 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151135 output('You need LGTM from owners of depends-on paths in DEPS that were '
1136 'modified in this CL:\n %s' %
1137 '\n '.join(sorted(unapproved_dependencies)))]
1138 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1139 output_list.append(output(
1140 'Suggested missing target path OWNERS:\n %s' %
1141 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551142 return output_list
1143
1144 return []
1145
1146
[email protected]85218562013-11-22 07:41:401147def _CheckSpamLogging(input_api, output_api):
1148 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1149 black_list = (_EXCLUDED_PATHS +
1150 _TEST_CODE_EXCLUDED_PATHS +
1151 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501152 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191153 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481154 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461155 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121156 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1157 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581158 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161159 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031160 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151161 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1162 r"^chromecast[\\\/]",
1163 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311164 r"^components[\\\/]html_viewer[\\\/]"
1165 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461166 # TODO(peter): Remove this exception. https://crbug.com/534537
1167 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1168 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251169 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1170 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241171 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111172 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151173 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111174 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521175 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501176 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361177 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311178 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131179 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441180 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451181 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021182 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351183 r"dump_file_system.cc$",
1184 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401185 source_file_filter = lambda x: input_api.FilterSourceFile(
1186 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1187
1188 log_info = []
1189 printf = []
1190
1191 for f in input_api.AffectedSourceFiles(source_file_filter):
1192 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471193 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401194 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471195 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131196 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371197
mohan.reddyf21db962014-10-16 12:26:471198 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371199 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471200 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401201 printf.append(f.LocalPath())
1202
1203 if log_info:
1204 return [output_api.PresubmitError(
1205 'These files spam the console log with LOG(INFO):',
1206 items=log_info)]
1207 if printf:
1208 return [output_api.PresubmitError(
1209 'These files spam the console log with printf/fprintf:',
1210 items=printf)]
1211 return []
1212
1213
[email protected]49aa76a2013-12-04 06:59:161214def _CheckForAnonymousVariables(input_api, output_api):
1215 """These types are all expected to hold locks while in scope and
1216 so should never be anonymous (which causes them to be immediately
1217 destroyed)."""
1218 they_who_must_be_named = [
1219 'base::AutoLock',
1220 'base::AutoReset',
1221 'base::AutoUnlock',
1222 'SkAutoAlphaRestore',
1223 'SkAutoBitmapShaderInstall',
1224 'SkAutoBlitterChoose',
1225 'SkAutoBounderCommit',
1226 'SkAutoCallProc',
1227 'SkAutoCanvasRestore',
1228 'SkAutoCommentBlock',
1229 'SkAutoDescriptor',
1230 'SkAutoDisableDirectionCheck',
1231 'SkAutoDisableOvalCheck',
1232 'SkAutoFree',
1233 'SkAutoGlyphCache',
1234 'SkAutoHDC',
1235 'SkAutoLockColors',
1236 'SkAutoLockPixels',
1237 'SkAutoMalloc',
1238 'SkAutoMaskFreeImage',
1239 'SkAutoMutexAcquire',
1240 'SkAutoPathBoundsUpdate',
1241 'SkAutoPDFRelease',
1242 'SkAutoRasterClipValidate',
1243 'SkAutoRef',
1244 'SkAutoTime',
1245 'SkAutoTrace',
1246 'SkAutoUnref',
1247 ]
1248 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1249 # bad: base::AutoLock(lock.get());
1250 # not bad: base::AutoLock lock(lock.get());
1251 bad_pattern = input_api.re.compile(anonymous)
1252 # good: new base::AutoLock(lock.get())
1253 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1254 errors = []
1255
1256 for f in input_api.AffectedFiles():
1257 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1258 continue
1259 for linenum, line in f.ChangedContents():
1260 if bad_pattern.search(line) and not good_pattern.search(line):
1261 errors.append('%s:%d' % (f.LocalPath(), linenum))
1262
1263 if errors:
1264 return [output_api.PresubmitError(
1265 'These lines create anonymous variables that need to be named:',
1266 items=errors)]
1267 return []
1268
1269
[email protected]5fe0f8742013-11-29 01:04:591270def _CheckCygwinShell(input_api, output_api):
1271 source_file_filter = lambda x: input_api.FilterSourceFile(
1272 x, white_list=(r'.+\.(gyp|gypi)$',))
1273 cygwin_shell = []
1274
1275 for f in input_api.AffectedSourceFiles(source_file_filter):
1276 for linenum, line in f.ChangedContents():
1277 if 'msvs_cygwin_shell' in line:
1278 cygwin_shell.append(f.LocalPath())
1279 break
1280
1281 if cygwin_shell:
1282 return [output_api.PresubmitError(
1283 'These files should not use msvs_cygwin_shell (the default is 0):',
1284 items=cygwin_shell)]
1285 return []
1286
[email protected]85218562013-11-22 07:41:401287
[email protected]999261d2014-03-03 20:08:081288def _CheckUserActionUpdate(input_api, output_api):
1289 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521290 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081291 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521292 # If actions.xml is already included in the changelist, the PRESUBMIT
1293 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081294 return []
1295
[email protected]999261d2014-03-03 20:08:081296 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1297 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521298 current_actions = None
[email protected]999261d2014-03-03 20:08:081299 for f in input_api.AffectedFiles(file_filter=file_filter):
1300 for line_num, line in f.ChangedContents():
1301 match = input_api.re.search(action_re, line)
1302 if match:
[email protected]2f92dec2014-03-07 19:21:521303 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1304 # loaded only once.
1305 if not current_actions:
1306 with open('tools/metrics/actions/actions.xml') as actions_f:
1307 current_actions = actions_f.read()
1308 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081309 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521310 action = 'name="{0}"'.format(action_name)
1311 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081312 return [output_api.PresubmitPromptWarning(
1313 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521314 'tools/metrics/actions/actions.xml. Please run '
1315 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081316 % (f.LocalPath(), line_num, action_name))]
1317 return []
1318
1319
[email protected]99171a92014-06-03 08:44:471320def _GetJSONParseError(input_api, filename, eat_comments=True):
1321 try:
1322 contents = input_api.ReadFile(filename)
1323 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131324 import sys
1325 original_sys_path = sys.path
1326 try:
1327 sys.path = sys.path + [input_api.os_path.join(
1328 input_api.PresubmitLocalPath(),
1329 'tools', 'json_comment_eater')]
1330 import json_comment_eater
1331 finally:
1332 sys.path = original_sys_path
1333 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471334
1335 input_api.json.loads(contents)
1336 except ValueError as e:
1337 return e
1338 return None
1339
1340
1341def _GetIDLParseError(input_api, filename):
1342 try:
1343 contents = input_api.ReadFile(filename)
1344 idl_schema = input_api.os_path.join(
1345 input_api.PresubmitLocalPath(),
1346 'tools', 'json_schema_compiler', 'idl_schema.py')
1347 process = input_api.subprocess.Popen(
1348 [input_api.python_executable, idl_schema],
1349 stdin=input_api.subprocess.PIPE,
1350 stdout=input_api.subprocess.PIPE,
1351 stderr=input_api.subprocess.PIPE,
1352 universal_newlines=True)
1353 (_, error) = process.communicate(input=contents)
1354 return error or None
1355 except ValueError as e:
1356 return e
1357
1358
1359def _CheckParseErrors(input_api, output_api):
1360 """Check that IDL and JSON files do not contain syntax errors."""
1361 actions = {
1362 '.idl': _GetIDLParseError,
1363 '.json': _GetJSONParseError,
1364 }
1365 # These paths contain test data and other known invalid JSON files.
1366 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491367 r'test[\\\/]data[\\\/]',
1368 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471369 ]
1370 # Most JSON files are preprocessed and support comments, but these do not.
1371 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491372 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471373 ]
1374 # Only run IDL checker on files in these directories.
1375 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491376 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1377 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471378 ]
1379
1380 def get_action(affected_file):
1381 filename = affected_file.LocalPath()
1382 return actions.get(input_api.os_path.splitext(filename)[1])
1383
1384 def MatchesFile(patterns, path):
1385 for pattern in patterns:
1386 if input_api.re.search(pattern, path):
1387 return True
1388 return False
1389
1390 def FilterFile(affected_file):
1391 action = get_action(affected_file)
1392 if not action:
1393 return False
1394 path = affected_file.LocalPath()
1395
1396 if MatchesFile(excluded_patterns, path):
1397 return False
1398
1399 if (action == _GetIDLParseError and
1400 not MatchesFile(idl_included_patterns, path)):
1401 return False
1402 return True
1403
1404 results = []
1405 for affected_file in input_api.AffectedFiles(
1406 file_filter=FilterFile, include_deletes=False):
1407 action = get_action(affected_file)
1408 kwargs = {}
1409 if (action == _GetJSONParseError and
1410 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1411 kwargs['eat_comments'] = False
1412 parse_error = action(input_api,
1413 affected_file.AbsoluteLocalPath(),
1414 **kwargs)
1415 if parse_error:
1416 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1417 (affected_file.LocalPath(), parse_error)))
1418 return results
1419
1420
[email protected]760deea2013-12-10 19:33:491421def _CheckJavaStyle(input_api, output_api):
1422 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471423 import sys
[email protected]760deea2013-12-10 19:33:491424 original_sys_path = sys.path
1425 try:
1426 sys.path = sys.path + [input_api.os_path.join(
1427 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1428 import checkstyle
1429 finally:
1430 # Restore sys.path to what it was before.
1431 sys.path = original_sys_path
1432
1433 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091434 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511435 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491436
1437
dchenge07de812016-06-20 19:27:171438def _CheckIpcOwners(input_api, output_api):
1439 """Checks that affected files involving IPC have an IPC OWNERS rule.
1440
1441 Whether or not a file affects IPC is determined by a simple whitelist of
1442 filename patterns."""
1443 file_patterns = [
1444 '*_messages.cc',
1445 '*_messages*.h',
1446 '*_param_traits*.*',
1447 '*.mojom',
1448 '*_struct_traits*.*',
1449 '*_type_converter*.*',
1450 # Blink uses a different file naming convention
1451 '*StructTraits*.*',
1452 '*TypeConverter*.*',
1453 ]
1454
scottmg7a6ed5ba2016-11-04 18:22:041455 # These third_party directories do not contain IPCs, but contain files
1456 # matching the above patterns, which trigger false positives.
1457 exclude_paths = [
1458 'third_party/crashpad/*',
1459 ]
1460
dchenge07de812016-06-20 19:27:171461 # Dictionary mapping an OWNERS file path to Patterns.
1462 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1463 # rules ) to a PatternEntry.
1464 # PatternEntry is a dictionary with two keys:
1465 # - 'files': the files that are matched by this pattern
1466 # - 'rules': the per-file rules needed for this pattern
1467 # For example, if we expect OWNERS file to contain rules for *.mojom and
1468 # *_struct_traits*.*, Patterns might look like this:
1469 # {
1470 # '*.mojom': {
1471 # 'files': ...,
1472 # 'rules': [
1473 # 'per-file *.mojom=set noparent',
1474 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1475 # ],
1476 # },
1477 # '*_struct_traits*.*': {
1478 # 'files': ...,
1479 # 'rules': [
1480 # 'per-file *_struct_traits*.*=set noparent',
1481 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1482 # ],
1483 # },
1484 # }
1485 to_check = {}
1486
1487 # Iterate through the affected files to see what we actually need to check
1488 # for. We should only nag patch authors about per-file rules if a file in that
1489 # directory would match that pattern. If a directory only contains *.mojom
1490 # files and no *_messages*.h files, we should only nag about rules for
1491 # *.mojom files.
rockot51249332016-06-23 16:32:251492 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171493 for pattern in file_patterns:
1494 if input_api.fnmatch.fnmatch(
1495 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041496 skip = False
1497 for exclude in exclude_paths:
1498 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1499 skip = True
1500 break
1501 if skip:
1502 continue
dchenge07de812016-06-20 19:27:171503 owners_file = input_api.os_path.join(
1504 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1505 if owners_file not in to_check:
1506 to_check[owners_file] = {}
1507 if pattern not in to_check[owners_file]:
1508 to_check[owners_file][pattern] = {
1509 'files': [],
1510 'rules': [
1511 'per-file %s=set noparent' % pattern,
1512 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1513 ]
1514 }
1515 to_check[owners_file][pattern]['files'].append(f)
1516 break
1517
1518 # Now go through the OWNERS files we collected, filtering out rules that are
1519 # already present in that OWNERS file.
1520 for owners_file, patterns in to_check.iteritems():
1521 try:
1522 with file(owners_file) as f:
1523 lines = set(f.read().splitlines())
1524 for entry in patterns.itervalues():
1525 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1526 ]
1527 except IOError:
1528 # No OWNERS file, so all the rules are definitely missing.
1529 continue
1530
1531 # All the remaining lines weren't found in OWNERS files, so emit an error.
1532 errors = []
1533 for owners_file, patterns in to_check.iteritems():
1534 missing_lines = []
1535 files = []
1536 for pattern, entry in patterns.iteritems():
1537 missing_lines.extend(entry['rules'])
1538 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1539 if missing_lines:
1540 errors.append(
1541 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1542 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1543
1544 results = []
1545 if errors:
vabrf5ce3bf92016-07-11 14:52:411546 if input_api.is_committing:
1547 output = output_api.PresubmitError
1548 else:
1549 output = output_api.PresubmitPromptWarning
1550 results.append(output(
dchenge07de812016-06-20 19:27:171551 'Found changes to IPC files without a security OWNER!',
1552 long_text='\n\n'.join(errors)))
1553
1554 return results
1555
1556
jbriance9e12f162016-11-25 07:57:501557def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311558 """Checks that added or removed lines in non third party affected
1559 header files do not lead to new useless class or struct forward
1560 declaration.
jbriance9e12f162016-11-25 07:57:501561 """
1562 results = []
1563 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1564 input_api.re.MULTILINE)
1565 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1566 input_api.re.MULTILINE)
1567 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311568 if (f.LocalPath().startswith('third_party') and
1569 not f.LocalPath().startswith('third_party/WebKit') and
1570 not f.LocalPath().startswith('third_party\\WebKit')):
1571 continue
1572
jbriance9e12f162016-11-25 07:57:501573 if not f.LocalPath().endswith('.h'):
1574 continue
1575
1576 contents = input_api.ReadFile(f)
1577 fwd_decls = input_api.re.findall(class_pattern, contents)
1578 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1579
1580 useless_fwd_decls = []
1581 for decl in fwd_decls:
1582 count = sum(1 for _ in input_api.re.finditer(
1583 r'\b%s\b' % input_api.re.escape(decl), contents))
1584 if count == 1:
1585 useless_fwd_decls.append(decl)
1586
1587 if not useless_fwd_decls:
1588 continue
1589
1590 for line in f.GenerateScmDiff().splitlines():
1591 if (line.startswith('-') and not line.startswith('--') or
1592 line.startswith('+') and not line.startswith('++')):
1593 for decl in useless_fwd_decls:
1594 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1595 results.append(output_api.PresubmitPromptWarning(
1596 '%s: %s forward declaration is becoming useless' %
1597 (f.LocalPath(), decl)))
1598 useless_fwd_decls.remove(decl)
1599
1600 return results
1601
1602
dskiba88634f4e2015-08-14 23:03:291603def _CheckAndroidToastUsage(input_api, output_api):
1604 """Checks that code uses org.chromium.ui.widget.Toast instead of
1605 android.widget.Toast (Chromium Toast doesn't force hardware
1606 acceleration on low-end devices, saving memory).
1607 """
1608 toast_import_pattern = input_api.re.compile(
1609 r'^import android\.widget\.Toast;$')
1610
1611 errors = []
1612
1613 sources = lambda affected_file: input_api.FilterSourceFile(
1614 affected_file,
1615 black_list=(_EXCLUDED_PATHS +
1616 _TEST_CODE_EXCLUDED_PATHS +
1617 input_api.DEFAULT_BLACK_LIST +
1618 (r'^chromecast[\\\/].*',
1619 r'^remoting[\\\/].*')),
1620 white_list=(r'.*\.java$',))
1621
1622 for f in input_api.AffectedSourceFiles(sources):
1623 for line_num, line in f.ChangedContents():
1624 if toast_import_pattern.search(line):
1625 errors.append("%s:%d" % (f.LocalPath(), line_num))
1626
1627 results = []
1628
1629 if errors:
1630 results.append(output_api.PresubmitError(
1631 'android.widget.Toast usage is detected. Android toasts use hardware'
1632 ' acceleration, and can be\ncostly on low-end devices. Please use'
1633 ' org.chromium.ui.widget.Toast instead.\n'
1634 'Contact [email protected] if you have any questions.',
1635 errors))
1636
1637 return results
1638
1639
dgnaa68d5e2015-06-10 10:08:221640def _CheckAndroidCrLogUsage(input_api, output_api):
1641 """Checks that new logs using org.chromium.base.Log:
1642 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511643 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221644 """
pkotwicza1dd0b002016-05-16 14:41:041645
1646 # Do not check format of logs in //chrome/android/webapk because
1647 # //chrome/android/webapk cannot depend on //base
1648 cr_log_check_excluded_paths = [
1649 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
1650 ]
1651
dgnaa68d5e2015-06-10 10:08:221652 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121653 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1654 class_in_base_pattern = input_api.re.compile(
1655 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1656 has_some_log_import_pattern = input_api.re.compile(
1657 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221658 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121659 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221660 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511661 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221662 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221663
Vincent Scheib16d7b272015-09-15 18:09:071664 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221665 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041666 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1667 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121668
dgnaa68d5e2015-06-10 10:08:221669 tag_decl_errors = []
1670 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121671 tag_errors = []
dgn38736db2015-09-18 19:20:511672 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121673 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221674
1675 for f in input_api.AffectedSourceFiles(sources):
1676 file_content = input_api.ReadFile(f)
1677 has_modified_logs = False
1678
1679 # Per line checks
dgn87d9fb62015-06-12 09:15:121680 if (cr_log_import_pattern.search(file_content) or
1681 (class_in_base_pattern.search(file_content) and
1682 not has_some_log_import_pattern.search(file_content))):
1683 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221684 for line_num, line in f.ChangedContents():
1685
1686 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121687 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221688 if match:
1689 has_modified_logs = True
1690
1691 # Make sure it uses "TAG"
1692 if not match.group('tag') == 'TAG':
1693 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121694 else:
1695 # Report non cr Log function calls in changed lines
1696 for line_num, line in f.ChangedContents():
1697 if log_call_pattern.search(line):
1698 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221699
1700 # Per file checks
1701 if has_modified_logs:
1702 # Make sure the tag is using the "cr" prefix and is not too long
1703 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511704 tag_name = match.group('name') if match else None
1705 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221706 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511707 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221708 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511709 elif '.' in tag_name:
1710 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221711
1712 results = []
1713 if tag_decl_errors:
1714 results.append(output_api.PresubmitPromptWarning(
1715 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511716 '"private static final String TAG = "<package tag>".\n'
1717 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221718 tag_decl_errors))
1719
1720 if tag_length_errors:
1721 results.append(output_api.PresubmitError(
1722 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511723 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221724 tag_length_errors))
1725
1726 if tag_errors:
1727 results.append(output_api.PresubmitPromptWarning(
1728 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1729 tag_errors))
1730
dgn87d9fb62015-06-12 09:15:121731 if util_log_errors:
dgn4401aa52015-04-29 16:26:171732 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121733 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1734 util_log_errors))
1735
dgn38736db2015-09-18 19:20:511736 if tag_with_dot_errors:
1737 results.append(output_api.PresubmitPromptWarning(
1738 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1739 tag_with_dot_errors))
1740
dgn4401aa52015-04-29 16:26:171741 return results
1742
1743
yolandyan45001472016-12-21 21:12:421744def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1745 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1746 deprecated_annotation_import_pattern = input_api.re.compile(
1747 r'^import android\.test\.suitebuilder\.annotation\..*;',
1748 input_api.re.MULTILINE)
1749 sources = lambda x: input_api.FilterSourceFile(
1750 x, white_list=(r'.*\.java$',), black_list=None)
1751 errors = []
1752 for f in input_api.AffectedFiles(sources):
1753 for line_num, line in f.ChangedContents():
1754 if deprecated_annotation_import_pattern.search(line):
1755 errors.append("%s:%d" % (f.LocalPath(), line_num))
1756
1757 results = []
1758 if errors:
1759 results.append(output_api.PresubmitError(
1760 'Annotations in android.test.suitebuilder.annotation have been'
1761 ' deprecated since API level 24. Please use android.support.test.filters'
1762 ' from //third_party/android_support_test_runner:runner_java instead.'
1763 ' Contact [email protected] if you have any questions.', errors))
1764 return results
1765
1766
agrieve7b6479d82015-10-07 14:24:221767def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1768 """Checks if MDPI assets are placed in a correct directory."""
1769 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1770 ('/res/drawable/' in f.LocalPath() or
1771 '/res/drawable-ldrtl/' in f.LocalPath()))
1772 errors = []
1773 for f in input_api.AffectedFiles(include_deletes=False,
1774 file_filter=file_filter):
1775 errors.append(' %s' % f.LocalPath())
1776
1777 results = []
1778 if errors:
1779 results.append(output_api.PresubmitError(
1780 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1781 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1782 '/res/drawable-ldrtl/.\n'
1783 'Contact [email protected] if you have questions.', errors))
1784 return results
1785
1786
agrievef32bcc72016-04-04 14:57:401787class PydepsChecker(object):
1788 def __init__(self, input_api, pydeps_files):
1789 self._file_cache = {}
1790 self._input_api = input_api
1791 self._pydeps_files = pydeps_files
1792
1793 def _LoadFile(self, path):
1794 """Returns the list of paths within a .pydeps file relative to //."""
1795 if path not in self._file_cache:
1796 with open(path) as f:
1797 self._file_cache[path] = f.read()
1798 return self._file_cache[path]
1799
1800 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1801 """Returns an interable of paths within the .pydep, relativized to //."""
1802 os_path = self._input_api.os_path
1803 pydeps_dir = os_path.dirname(pydeps_path)
1804 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1805 if not l.startswith('*'))
1806 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1807
1808 def _CreateFilesToPydepsMap(self):
1809 """Returns a map of local_path -> list_of_pydeps."""
1810 ret = {}
1811 for pydep_local_path in self._pydeps_files:
1812 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1813 ret.setdefault(path, []).append(pydep_local_path)
1814 return ret
1815
1816 def ComputeAffectedPydeps(self):
1817 """Returns an iterable of .pydeps files that might need regenerating."""
1818 affected_pydeps = set()
1819 file_to_pydeps_map = None
1820 for f in self._input_api.AffectedFiles(include_deletes=True):
1821 local_path = f.LocalPath()
1822 if local_path == 'DEPS':
1823 return self._pydeps_files
1824 elif local_path.endswith('.pydeps'):
1825 if local_path in self._pydeps_files:
1826 affected_pydeps.add(local_path)
1827 elif local_path.endswith('.py'):
1828 if file_to_pydeps_map is None:
1829 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1830 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1831 return affected_pydeps
1832
1833 def DetermineIfStale(self, pydeps_path):
1834 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411835 import difflib
agrievef32bcc72016-04-04 14:57:401836 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1837 cmd = old_pydeps_data[1][1:].strip()
1838 new_pydeps_data = self._input_api.subprocess.check_output(
1839 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411840 old_contents = old_pydeps_data[2:]
1841 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401842 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411843 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401844
1845
1846def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1847 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001848 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281849 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1850 # Mac, so skip it on other platforms.
1851 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001852 return []
agrievef32bcc72016-04-04 14:57:401853 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1854 is_android = input_api.os_path.exists('third_party/android_tools')
1855 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1856 results = []
1857 # First, check for new / deleted .pydeps.
1858 for f in input_api.AffectedFiles(include_deletes=True):
1859 if f.LocalPath().endswith('.pydeps'):
1860 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1861 results.append(output_api.PresubmitError(
1862 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1863 'remove %s' % f.LocalPath()))
1864 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1865 results.append(output_api.PresubmitError(
1866 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1867 'include %s' % f.LocalPath()))
1868
1869 if results:
1870 return results
1871
1872 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1873
1874 for pydep_path in checker.ComputeAffectedPydeps():
1875 try:
phajdan.jr0d9878552016-11-04 10:49:411876 result = checker.DetermineIfStale(pydep_path)
1877 if result:
1878 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401879 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411880 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1881 'To regenerate, run:\n\n %s' %
1882 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401883 except input_api.subprocess.CalledProcessError as error:
1884 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1885 long_text=error.output)]
1886
1887 return results
1888
1889
glidere61efad2015-02-18 17:39:431890def _CheckSingletonInHeaders(input_api, output_api):
1891 """Checks to make sure no header files have |Singleton<|."""
1892 def FileFilter(affected_file):
1893 # It's ok for base/memory/singleton.h to have |Singleton<|.
1894 black_list = (_EXCLUDED_PATHS +
1895 input_api.DEFAULT_BLACK_LIST +
1896 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1897 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1898
sergeyu34d21222015-09-16 00:11:441899 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431900 files = []
1901 for f in input_api.AffectedSourceFiles(FileFilter):
1902 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1903 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1904 contents = input_api.ReadFile(f)
1905 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241906 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431907 pattern.search(line)):
1908 files.append(f)
1909 break
1910
1911 if files:
yolandyandaabc6d2016-04-18 18:29:391912 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441913 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431914 'Please move them to an appropriate source file so that the ' +
1915 'template gets instantiated in a single compilation unit.',
1916 files) ]
1917 return []
1918
1919
dbeam1ec68ac2016-12-15 05:22:241920def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:201921 """Checks for old style compiled_resources.gyp files."""
1922 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1923
1924 added_compiled_resources = filter(is_compiled_resource, [
1925 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1926 ])
1927
1928 if not added_compiled_resources:
1929 return []
1930
1931 return [output_api.PresubmitError(
1932 "Found new compiled_resources.gyp files:\n%s\n\n"
1933 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551934 "please use compiled_resources2.gyp instead:\n"
1935 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1936 %
dbeam37e8e7402016-02-10 22:58:201937 "\n".join(added_compiled_resources))]
1938
1939
[email protected]fd20b902014-05-09 02:14:531940_DEPRECATED_CSS = [
1941 # Values
1942 ( "-webkit-box", "flex" ),
1943 ( "-webkit-inline-box", "inline-flex" ),
1944 ( "-webkit-flex", "flex" ),
1945 ( "-webkit-inline-flex", "inline-flex" ),
1946 ( "-webkit-min-content", "min-content" ),
1947 ( "-webkit-max-content", "max-content" ),
1948
1949 # Properties
1950 ( "-webkit-background-clip", "background-clip" ),
1951 ( "-webkit-background-origin", "background-origin" ),
1952 ( "-webkit-background-size", "background-size" ),
1953 ( "-webkit-box-shadow", "box-shadow" ),
1954
1955 # Functions
1956 ( "-webkit-gradient", "gradient" ),
1957 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1958 ( "-webkit-linear-gradient", "linear-gradient" ),
1959 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1960 ( "-webkit-radial-gradient", "radial-gradient" ),
1961 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1962]
1963
dbeam1ec68ac2016-12-15 05:22:241964def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531965 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251966 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341967 documentation and iOS CSS for dom distiller
1968 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251969 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531970 results = []
dbeam070cfe62014-10-22 06:44:021971 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251972 black_list = (_EXCLUDED_PATHS +
1973 _TEST_CODE_EXCLUDED_PATHS +
1974 input_api.DEFAULT_BLACK_LIST +
1975 (r"^chrome/common/extensions/docs",
1976 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341977 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051978 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441979 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251980 r"^native_client_sdk"))
1981 file_filter = lambda f: input_api.FilterSourceFile(
1982 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531983 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1984 for line_num, line in fpath.ChangedContents():
1985 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021986 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531987 results.append(output_api.PresubmitError(
1988 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1989 (fpath.LocalPath(), line_num, deprecated_value, value)))
1990 return results
1991
mohan.reddyf21db962014-10-16 12:26:471992
dbeam070cfe62014-10-22 06:44:021993_DEPRECATED_JS = [
1994 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1995 ( "__defineGetter__", "Object.defineProperty" ),
1996 ( "__defineSetter__", "Object.defineProperty" ),
1997]
1998
dbeam1ec68ac2016-12-15 05:22:241999def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022000 """Make sure that we don't use deprecated JS in Chrome code."""
2001 results = []
2002 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2003 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2004 input_api.DEFAULT_BLACK_LIST)
2005 file_filter = lambda f: input_api.FilterSourceFile(
2006 f, white_list=file_inclusion_pattern, black_list=black_list)
2007 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2008 for lnum, line in fpath.ChangedContents():
2009 for (deprecated, replacement) in _DEPRECATED_JS:
2010 if deprecated in line:
2011 results.append(output_api.PresubmitError(
2012 "%s:%d: Use of deprecated JS %s, use %s instead" %
2013 (fpath.LocalPath(), lnum, deprecated, replacement)))
2014 return results
2015
2016
dbeam1ec68ac2016-12-15 05:22:242017def _CheckForRiskyJsFeatures(input_api, output_api):
2018 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2019 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2020
2021 arrow_lines = []
2022 for f in input_api.AffectedFiles(file_filter=file_filter):
2023 for lnum, line in f.ChangedContents():
2024 if ' => ' in line:
2025 arrow_lines.append((f.LocalPath(), lnum))
2026
2027 if not arrow_lines:
2028 return []
2029
2030 return [output_api.PresubmitPromptWarning("""
2031Use of => operator detected in:
2032%s
2033Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2034https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2035""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2036
2037
dgnaa68d5e2015-06-10 10:08:222038def _AndroidSpecificOnUploadChecks(input_api, output_api):
2039 """Groups checks that target android code."""
2040 results = []
dgnaa68d5e2015-06-10 10:08:222041 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222042 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292043 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422044 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222045 return results
2046
2047
[email protected]22c9bd72011-03-27 16:47:392048def _CommonChecks(input_api, output_api):
2049 """Checks common to both upload and commit."""
2050 results = []
2051 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382052 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542053 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582054 results.extend(
2055 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192056 results.extend(
[email protected]760deea2013-12-10 19:33:492057 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542058 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182059 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522060 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222061 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442062 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592063 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062064 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122065 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182066 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222067 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302068 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492069 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272070 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032071 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492072 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442073 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272074 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542075 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442076 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392077 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552078 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042079 results.extend(
2080 input_api.canned_checks.CheckChangeHasNoTabs(
2081 input_api,
2082 output_api,
2083 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402084 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162085 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592086 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082087 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242088 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2089 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472090 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042091 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232092 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432093 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242094 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402095 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152096 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172097 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502098 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242099 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242100
2101 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2102 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2103 input_api, output_api,
2104 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382105 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392106 return results
[email protected]1f7b4172010-01-28 01:17:342107
[email protected]b337cb5b2011-01-23 21:24:052108
[email protected]b8079ae4a2012-12-05 19:56:492109def _CheckPatchFiles(input_api, output_api):
2110 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2111 if f.LocalPath().endswith(('.orig', '.rej'))]
2112 if problems:
2113 return [output_api.PresubmitError(
2114 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032115 else:
2116 return []
[email protected]b8079ae4a2012-12-05 19:56:492117
2118
[email protected]b00342e7f2013-03-26 16:21:542119def _DidYouMeanOSMacro(bad_macro):
2120 try:
2121 return {'A': 'OS_ANDROID',
2122 'B': 'OS_BSD',
2123 'C': 'OS_CHROMEOS',
2124 'F': 'OS_FREEBSD',
2125 'L': 'OS_LINUX',
2126 'M': 'OS_MACOSX',
2127 'N': 'OS_NACL',
2128 'O': 'OS_OPENBSD',
2129 'P': 'OS_POSIX',
2130 'S': 'OS_SOLARIS',
2131 'W': 'OS_WIN'}[bad_macro[3].upper()]
2132 except KeyError:
2133 return ''
2134
2135
2136def _CheckForInvalidOSMacrosInFile(input_api, f):
2137 """Check for sensible looking, totally invalid OS macros."""
2138 preprocessor_statement = input_api.re.compile(r'^\s*#')
2139 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2140 results = []
2141 for lnum, line in f.ChangedContents():
2142 if preprocessor_statement.search(line):
2143 for match in os_macro.finditer(line):
2144 if not match.group(1) in _VALID_OS_MACROS:
2145 good = _DidYouMeanOSMacro(match.group(1))
2146 did_you_mean = ' (did you mean %s?)' % good if good else ''
2147 results.append(' %s:%d %s%s' % (f.LocalPath(),
2148 lnum,
2149 match.group(1),
2150 did_you_mean))
2151 return results
2152
2153
2154def _CheckForInvalidOSMacros(input_api, output_api):
2155 """Check all affected files for invalid OS macros."""
2156 bad_macros = []
2157 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472158 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542159 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2160
2161 if not bad_macros:
2162 return []
2163
2164 return [output_api.PresubmitError(
2165 'Possibly invalid OS macro[s] found. Please fix your code\n'
2166 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2167
lliabraa35bab3932014-10-01 12:16:442168
2169def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2170 """Check all affected files for invalid "if defined" macros."""
2171 ALWAYS_DEFINED_MACROS = (
2172 "TARGET_CPU_PPC",
2173 "TARGET_CPU_PPC64",
2174 "TARGET_CPU_68K",
2175 "TARGET_CPU_X86",
2176 "TARGET_CPU_ARM",
2177 "TARGET_CPU_MIPS",
2178 "TARGET_CPU_SPARC",
2179 "TARGET_CPU_ALPHA",
2180 "TARGET_IPHONE_SIMULATOR",
2181 "TARGET_OS_EMBEDDED",
2182 "TARGET_OS_IPHONE",
2183 "TARGET_OS_MAC",
2184 "TARGET_OS_UNIX",
2185 "TARGET_OS_WIN32",
2186 )
2187 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2188 results = []
2189 for lnum, line in f.ChangedContents():
2190 for match in ifdef_macro.finditer(line):
2191 if match.group(1) in ALWAYS_DEFINED_MACROS:
2192 always_defined = ' %s is always defined. ' % match.group(1)
2193 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2194 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2195 lnum,
2196 always_defined,
2197 did_you_mean))
2198 return results
2199
2200
2201def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2202 """Check all affected files for invalid "if defined" macros."""
2203 bad_macros = []
2204 for f in input_api.AffectedFiles():
2205 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2206 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2207
2208 if not bad_macros:
2209 return []
2210
2211 return [output_api.PresubmitError(
2212 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2213 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2214 bad_macros)]
2215
2216
mlamouria82272622014-09-16 18:45:042217def _CheckForIPCRules(input_api, output_api):
2218 """Check for same IPC rules described in
2219 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2220 """
2221 base_pattern = r'IPC_ENUM_TRAITS\('
2222 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2223 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2224
2225 problems = []
2226 for f in input_api.AffectedSourceFiles(None):
2227 local_path = f.LocalPath()
2228 if not local_path.endswith('.h'):
2229 continue
2230 for line_number, line in f.ChangedContents():
2231 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2232 problems.append(
2233 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2234
2235 if problems:
2236 return [output_api.PresubmitPromptWarning(
2237 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2238 else:
2239 return []
2240
[email protected]b00342e7f2013-03-26 16:21:542241
mostynbb639aca52015-01-07 20:31:232242def _CheckForWindowsLineEndings(input_api, output_api):
2243 """Check source code and known ascii text files for Windows style line
2244 endings.
2245 """
earthdok1b5e0ee2015-03-10 15:19:102246 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232247
2248 file_inclusion_pattern = (
2249 known_text_files,
2250 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2251 )
2252
2253 filter = lambda f: input_api.FilterSourceFile(
2254 f, white_list=file_inclusion_pattern, black_list=None)
2255 files = [f.LocalPath() for f in
2256 input_api.AffectedSourceFiles(filter)]
2257
2258 problems = []
2259
2260 for file in files:
2261 fp = open(file, 'r')
2262 for line in fp:
2263 if line.endswith('\r\n'):
2264 problems.append(file)
2265 break
2266 fp.close()
2267
2268 if problems:
2269 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2270 'these files to contain Windows style line endings?\n' +
2271 '\n'.join(problems))]
2272
2273 return []
2274
2275
pastarmovj89f7ee12016-09-20 14:58:132276def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2277 lint_filters=None, verbose_level=None):
2278 """Checks that all source files use SYSLOG properly."""
2279 syslog_files = []
2280 for f in input_api.AffectedSourceFiles(source_file_filter):
2281 if 'SYSLOG' in input_api.ReadFile(f, 'rb'):
2282 syslog_files.append(f.LocalPath())
2283 if syslog_files:
2284 return [output_api.PresubmitPromptWarning(
2285 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2286 ' calls.\nFiles to check:\n', items=syslog_files)]
2287 return []
2288
2289
[email protected]1f7b4172010-01-28 01:17:342290def CheckChangeOnUpload(input_api, output_api):
2291 results = []
2292 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472293 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282294 results.extend(
2295 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192296 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222297 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132298 results.extend(_CheckSyslogUseWarning(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542299 return results
[email protected]ca8d19842009-02-19 16:33:122300
2301
[email protected]1bfb8322014-04-23 01:02:412302def GetTryServerMasterForBot(bot):
2303 """Returns the Try Server master for the given bot.
2304
[email protected]0bb112362014-07-26 04:38:322305 It tries to guess the master from the bot name, but may still fail
2306 and return None. There is no longer a default master.
2307 """
2308 # Potentially ambiguous bot names are listed explicitly.
2309 master_map = {
tandriie5587792016-07-14 00:34:502310 'chromium_presubmit': 'master.tryserver.chromium.linux',
2311 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412312 }
[email protected]0bb112362014-07-26 04:38:322313 master = master_map.get(bot)
2314 if not master:
wnwen4fbaab82016-05-25 12:54:362315 if 'android' in bot:
tandriie5587792016-07-14 00:34:502316 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362317 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502318 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322319 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502320 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322321 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502322 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322323 return master
[email protected]1bfb8322014-04-23 01:02:412324
2325
Paweł Hajdan, Jr55083782014-12-19 20:32:562326def GetDefaultTryConfigs(bots):
2327 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012328 """
2329
Paweł Hajdan, Jr55083782014-12-19 20:32:562330 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412331
2332 # Build up the mapping from tryserver master to bot/test.
2333 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562334 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412335 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2336 return out
[email protected]38c6a512013-12-18 23:48:012337
2338
[email protected]ca8d19842009-02-19 16:33:122339def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542340 results = []
[email protected]1f7b4172010-01-28 01:17:342341 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542342 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272343 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342344 input_api,
2345 output_api,
[email protected]2fdd1f362013-01-16 03:56:032346 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272347
[email protected]3e4eb112011-01-18 03:29:542348 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2349 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412350 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2351 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542352 return results