blob: e44281b3630af67fd40ebcb2914e7602fb00b971 [file] [log] [blame]
K. Moon5e33cbd2022-10-31 19:22:36 +00001# Copyright 2015 The PDFium Authors
Nico Weber077f1a32015-08-06 15:08:57 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Presubmit script for pdfium.
6
7See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8for more details about the presubmit API built into depot_tools.
9"""
10
K. Moon5e33cbd2022-10-31 19:22:36 +000011PRESUBMIT_VERSION = '2.0.0'
12
Lei Zhangac238df2021-06-15 21:44:05 +000013USE_PYTHON3 = True
14
Dan Sinclair22d66072016-02-22 11:56:05 -050015LINT_FILTERS = [
Dan Sinclair3ebd1212016-03-09 09:59:23 -050016 # Rvalue ref checks are unreliable.
dan sinclaird2019df2016-02-22 22:32:03 -050017 '-build/c++11',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050018 # Need to fix header names not matching cpp names.
dan sinclaird2019df2016-02-22 22:32:03 -050019 '-build/include_order',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050020 # Too many to fix at the moment.
dan sinclaird2019df2016-02-22 22:32:03 -050021 '-readability/casting',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050022 # Need to refactor large methods to fix.
dan sinclaird2019df2016-02-22 22:32:03 -050023 '-readability/fn_size',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050024 # Lots of usage to fix first.
dan sinclaird2019df2016-02-22 22:32:03 -050025 '-runtime/int',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050026 # Lots of non-const references need to be fixed
dan sinclaird2019df2016-02-22 22:32:03 -050027 '-runtime/references',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050028 # We are not thread safe, so this will never pass.
dan sinclaird2019df2016-02-22 22:32:03 -050029 '-runtime/threadsafe_fn',
Dan Sinclair3ebd1212016-03-09 09:59:23 -050030 # Figure out how to deal with #defines that git cl format creates.
dan sinclaird2019df2016-02-22 22:32:03 -050031 '-whitespace/indent',
Dan Sinclair22d66072016-02-22 11:56:05 -050032]
33
Dan Sinclair544bbc62016-03-14 15:07:39 -040034
dsinclair2ca2da52016-09-13 18:10:34 -070035_INCLUDE_ORDER_WARNING = (
36 'Your #include order seems to be broken. Remember to use the right '
37 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
38 'cppguide.html#Names_and_Order_of_Includes')
39
40
Lei Zhang71e26732020-05-21 21:03:05 +000041# Bypass the AUTHORS check for these accounts.
42_KNOWN_ROBOTS = set() | set(
43 '%s@skia-public.iam.gserviceaccount.com' % s for s in ('pdfium-autoroll',))
44
Daniel Hosseinianb3bdbd42021-10-22 17:01:14 +000045_THIRD_PARTY = 'third_party/'
46
47# Format: Sequence of tuples containing:
48# * String pattern or, if starting with a slash, a regular expression.
49# * Sequence of strings to show when the pattern matches.
50# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
51# * Sequence of paths to *not* check (regexps).
52_BANNED_CPP_FUNCTIONS = (
53 (
54 r'/\busing namespace ',
55 (
K. Moon5e33cbd2022-10-31 19:22:36 +000056 'Using directives ("using namespace x") are banned by the Google',
57 'Style Guide (',
58 'https://google.github.io/styleguide/cppguide.html#Namespaces ).',
59 'Explicitly qualify symbols or use using declarations ("using',
60 'x::foo").',
Daniel Hosseinianb3bdbd42021-10-22 17:01:14 +000061 ),
62 True,
63 [_THIRD_PARTY],
64 ),
65 (
Daniel Hosseiniand7655382021-11-30 18:11:39 +000066 r'/v8::Isolate::(?:|Try)GetCurrent()',
Daniel Hosseinianb3bdbd42021-10-22 17:01:14 +000067 (
K. Moon5e33cbd2022-10-31 19:22:36 +000068 'v8::Isolate::GetCurrent() and v8::Isolate::TryGetCurrent() are',
69 'banned. Hold a pointer to the v8::Isolate that was entered. Use',
70 'v8::Isolate::IsCurrent() to check whether a given v8::Isolate is',
71 'entered.',
Daniel Hosseinianb3bdbd42021-10-22 17:01:14 +000072 ),
Daniel Hosseiniand7655382021-11-30 18:11:39 +000073 True,
Daniel Hosseinianb3bdbd42021-10-22 17:01:14 +000074 (),
75 ),
76)
77
78
79def _CheckNoBannedFunctions(input_api, output_api):
80 """Makes sure that banned functions are not used."""
81 warnings = []
82 errors = []
83
84 def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
85 type_name, message):
86 """Returns an string composed of the name of the file, the line number where
87 the match has been found and the additional text passed as `message` in case
88 the target type name matches the text inside the line passed as parameter.
89 """
90 result = []
91
92 if input_api.re.search(r"^ *//",
93 line): # Ignore comments about banned types.
94 return result
95 if line.endswith(
96 " nocheck"): # A // nocheck comment will bypass this error.
97 return result
98
99 matched = False
100 if type_name[0:1] == '/':
101 regex = type_name[1:]
102 if input_api.re.search(regex, line):
103 matched = True
104 elif type_name in line:
105 matched = True
106
107 if matched:
108 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
109 for message_line in message:
110 result.append(' %s' % message_line)
111
112 return result
113
114 def IsExcludedFile(affected_file, excluded_paths):
115 local_path = affected_file.LocalPath()
116 for item in excluded_paths:
117 if input_api.re.match(item, local_path):
118 return True
119 return False
120
121 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
122 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
123 func_name, message)
124 if problems:
125 if error:
126 errors.extend(problems)
127 else:
128 warnings.extend(problems)
129
130 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.cpp', '.h'))
131 for f in input_api.AffectedFiles(file_filter=file_filter):
132 for line_num, line in f.ChangedContents():
133 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
134 if IsExcludedFile(f, excluded_paths):
135 continue
136 CheckForMatch(f, line_num, line, func_name, message, error)
137
138 result = []
139 if (warnings):
140 result.append(
141 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
142 '\n'.join(warnings)))
143 if (errors):
144 result.append(
145 output_api.PresubmitError('Banned functions were used.\n' +
146 '\n'.join(errors)))
147 return result
148
Lei Zhang71e26732020-05-21 21:03:05 +0000149
Dan Sinclair544bbc62016-03-14 15:07:39 -0400150def _CheckUnwantedDependencies(input_api, output_api):
151 """Runs checkdeps on #include statements added in this
152 change. Breaking - rules is an error, breaking ! rules is a
153 warning.
154 """
155 import sys
156 # We need to wait until we have an input_api object and use this
157 # roundabout construct to import checkdeps because this file is
158 # eval-ed and thus doesn't have __file__.
159 original_sys_path = sys.path
160 try:
Lei Zhangb1d78722018-02-02 22:17:58 +0000161 def GenerateCheckdepsPath(base_path):
162 return input_api.os_path.join(base_path, 'buildtools', 'checkdeps')
163
164 presubmit_path = input_api.PresubmitLocalPath()
165 presubmit_parent_path = input_api.os_path.dirname(presubmit_path)
166 not_standalone_pdfium = \
167 input_api.os_path.basename(presubmit_parent_path) == "third_party" and \
168 input_api.os_path.basename(presubmit_path) == "pdfium"
169
170 sys.path.append(GenerateCheckdepsPath(presubmit_path))
171 if not_standalone_pdfium:
172 presubmit_grandparent_path = input_api.os_path.dirname(
173 presubmit_parent_path)
174 sys.path.append(GenerateCheckdepsPath(presubmit_grandparent_path))
175
Dan Sinclair544bbc62016-03-14 15:07:39 -0400176 import checkdeps
177 from cpp_checker import CppChecker
178 from rules import Rule
dsinclair4cd49e12016-04-05 10:28:48 -0700179 except ImportError:
180 return [output_api.PresubmitError(
181 'Unable to run checkdeps, does pdfium/buildtools/checkdeps exist?')]
Dan Sinclair544bbc62016-03-14 15:07:39 -0400182 finally:
183 # Restore sys.path to what it was before.
184 sys.path = original_sys_path
185
186 added_includes = []
187 for f in input_api.AffectedFiles():
188 if not CppChecker.IsCppFile(f.LocalPath()):
189 continue
190
191 changed_lines = [line for line_num, line in f.ChangedContents()]
192 added_includes.append([f.LocalPath(), changed_lines])
193
194 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
195
196 error_descriptions = []
197 warning_descriptions = []
198 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
199 added_includes):
200 description_with_path = '%s\n %s' % (path, rule_description)
201 if rule_type == Rule.DISALLOW:
202 error_descriptions.append(description_with_path)
203 else:
204 warning_descriptions.append(description_with_path)
205
206 results = []
207 if error_descriptions:
208 results.append(output_api.PresubmitError(
209 'You added one or more #includes that violate checkdeps rules.',
210 error_descriptions))
211 if warning_descriptions:
212 results.append(output_api.PresubmitPromptOrNotify(
213 'You added one or more #includes of files that are temporarily\n'
214 'allowed but being removed. Can you avoid introducing the\n'
215 '#include? See relevant DEPS file(s) for details and contacts.',
216 warning_descriptions))
217 return results
218
219
dsinclair2ca2da52016-09-13 18:10:34 -0700220def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
221 """Checks that the lines in scope occur in the right order.
222
223 1. C system files in alphabetical order
224 2. C++ system files in alphabetical order
225 3. Project's .h files
226 """
227
228 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
229 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
230 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
231
232 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
233
234 state = C_SYSTEM_INCLUDES
235
236 previous_line = ''
237 previous_line_num = 0
238 problem_linenums = []
239 out_of_order = " - line belongs before previous line"
240 for line_num, line in scope:
241 if c_system_include_pattern.match(line):
242 if state != C_SYSTEM_INCLUDES:
243 problem_linenums.append((line_num, previous_line_num,
244 " - C system include file in wrong block"))
245 elif previous_line and previous_line > line:
246 problem_linenums.append((line_num, previous_line_num,
247 out_of_order))
248 elif cpp_system_include_pattern.match(line):
249 if state == C_SYSTEM_INCLUDES:
250 state = CPP_SYSTEM_INCLUDES
251 elif state == CUSTOM_INCLUDES:
252 problem_linenums.append((line_num, previous_line_num,
253 " - c++ system include file in wrong block"))
254 elif previous_line and previous_line > line:
255 problem_linenums.append((line_num, previous_line_num, out_of_order))
256 elif custom_include_pattern.match(line):
257 if state != CUSTOM_INCLUDES:
258 state = CUSTOM_INCLUDES
259 elif previous_line and previous_line > line:
260 problem_linenums.append((line_num, previous_line_num, out_of_order))
261 else:
262 problem_linenums.append((line_num, previous_line_num,
263 "Unknown include type"))
264 previous_line = line
265 previous_line_num = line_num
266
267 warnings = []
268 for (line_num, previous_line_num, failure_type) in problem_linenums:
269 if line_num in changed_linenums or previous_line_num in changed_linenums:
270 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
271 return warnings
272
273
274def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
275 """Checks the #include order for the given file f."""
276
277 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
278 # Exclude the following includes from the check:
279 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
280 # specific order.
281 # 2) <atlbase.h>, "build/build_config.h"
282 excluded_include_pattern = input_api.re.compile(
283 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
284 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
285 # Match the final or penultimate token if it is xxxtest so we can ignore it
286 # when considering the special first include.
287 test_file_tag_pattern = input_api.re.compile(
288 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
289 if_pattern = input_api.re.compile(
290 r'\s*#\s*(if|elif|else|endif|define|undef).*')
291 # Some files need specialized order of includes; exclude such files from this
292 # check.
293 uncheckable_includes_pattern = input_api.re.compile(
294 r'\s*#include '
295 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
296
297 contents = f.NewContents()
298 warnings = []
299 line_num = 0
300
301 # Handle the special first include. If the first include file is
302 # some/path/file.h, the corresponding including file can be some/path/file.cc,
303 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
304 # etc. It's also possible that no special first include exists.
305 # If the included file is some/path/file_platform.h the including file could
306 # also be some/path/file_xxxtest_platform.h.
307 including_file_base_name = test_file_tag_pattern.sub(
308 '', input_api.os_path.basename(f.LocalPath()))
309
310 for line in contents:
311 line_num += 1
312 if system_include_pattern.match(line):
313 # No special first include -> process the line again along with normal
314 # includes.
315 line_num -= 1
316 break
317 match = custom_include_pattern.match(line)
318 if match:
319 match_dict = match.groupdict()
320 header_basename = test_file_tag_pattern.sub(
321 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
322
323 if header_basename not in including_file_base_name:
324 # No special first include -> process the line again along with normal
325 # includes.
326 line_num -= 1
327 break
328
329 # Split into scopes: Each region between #if and #endif is its own scope.
330 scopes = []
331 current_scope = []
332 for line in contents[line_num:]:
333 line_num += 1
334 if uncheckable_includes_pattern.match(line):
335 continue
336 if if_pattern.match(line):
337 scopes.append(current_scope)
338 current_scope = []
339 elif ((system_include_pattern.match(line) or
340 custom_include_pattern.match(line)) and
341 not excluded_include_pattern.match(line)):
342 current_scope.append((line_num, line))
343 scopes.append(current_scope)
344
345 for scope in scopes:
346 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
347 changed_linenums))
348 return warnings
349
350
351def _CheckIncludeOrder(input_api, output_api):
352 """Checks that the #include order is correct.
353
354 1. The corresponding header for source files.
355 2. C system files in alphabetical order
356 3. C++ system files in alphabetical order
357 4. Project's .h files in alphabetical order
358
359 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
360 these rules separately.
361 """
dsinclair2ca2da52016-09-13 18:10:34 -0700362 warnings = []
Lei Zhangf98bc4a2020-08-24 23:47:16 +0000363 for f in input_api.AffectedFiles(file_filter=input_api.FilterSourceFile):
dsinclaird33c8e32016-11-21 13:31:16 -0800364 if f.LocalPath().endswith(('.cc', '.cpp', '.h', '.mm')):
dsinclair2ca2da52016-09-13 18:10:34 -0700365 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
366 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
367
368 results = []
369 if warnings:
370 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
371 warnings))
372 return results
373
Lei Zhangf98bc4a2020-08-24 23:47:16 +0000374
Lei Zhang07ef29a2022-09-10 06:52:25 +0000375def _CheckLibcxxRevision(input_api, output_api):
376 """Makes sure that libcxx_revision is set correctly."""
377 if 'DEPS' not in [f.LocalPath() for f in input_api.AffectedFiles()]:
378 return []
379
380 script_path = input_api.os_path.join('testing', 'tools', 'libcxx_check.py')
381 buildtools_deps_path = input_api.os_path.join('buildtools',
382 'deps_revisions.gni')
383
384 try:
385 errors = input_api.subprocess.check_output(
386 [script_path, 'DEPS', buildtools_deps_path])
387 except input_api.subprocess.CalledProcessError as error:
388 msg = 'libcxx_check.py failed:'
389 long_text = error.output.decode('utf-8', 'ignore')
390 return [output_api.PresubmitError(msg, long_text=long_text)]
391
392 if errors:
393 return [output_api.PresubmitError(errors)]
394 return []
395
396
Nicolas Penad824a902017-05-19 15:59:49 -0400397def _CheckTestDuplicates(input_api, output_api):
398 """Checks that pixel and javascript tests don't contain duplicates.
399 We use .in and .pdf files, having both can cause race conditions on the bots,
400 which run the tests in parallel.
401 """
402 tests_added = []
403 results = []
404 for f in input_api.AffectedFiles():
Lei Zhang567039b2019-09-17 00:45:23 +0000405 if f.Action() == 'D':
406 continue
Nicolas Penad824a902017-05-19 15:59:49 -0400407 if not f.LocalPath().startswith(('testing/resources/pixel/',
408 'testing/resources/javascript/')):
409 continue
410 end_len = 0
411 if f.LocalPath().endswith('.in'):
412 end_len = 3
413 elif f.LocalPath().endswith('.pdf'):
414 end_len = 4
415 else:
416 continue
Nicolas Penac4479c52017-06-26 11:45:06 -0400417 path = f.LocalPath()[:-end_len]
Nicolas Penad824a902017-05-19 15:59:49 -0400418 if path in tests_added:
419 results.append(output_api.PresubmitError(
420 'Remove %s to prevent shadowing %s' % (path + '.pdf',
421 path + '.in')))
422 else:
423 tests_added.append(path)
424 return results
425
Lei Zhang624fba82021-06-15 20:11:39 +0000426
Nicolas Penac4479c52017-06-26 11:45:06 -0400427def _CheckPNGFormat(input_api, output_api):
428 """Checks that .png files have a format that will be considered valid by our
429 test runners. If a file ends with .png, then it must be of the form
K. Moon1a0e4da2022-11-29 21:00:35 +0000430 NAME_expected(_skia)?(_(win|mac|linux))?.pdf.#.png
Hui Yingst5d5273f2021-10-01 17:58:33 +0000431 The expected format used by _CheckPngNames() in testing/corpus/PRESUBMIT.py
432 must be the same as this one.
433 """
Nicolas Penac4479c52017-06-26 11:45:06 -0400434 expected_pattern = input_api.re.compile(
K. Moon1a0e4da2022-11-29 21:00:35 +0000435 r'.+_expected(_skia)?(_(win|mac|linux))?\.pdf\.\d+.png')
Nicolas Penac4479c52017-06-26 11:45:06 -0400436 results = []
Nicolas Penad261b062017-06-26 16:54:43 -0400437 for f in input_api.AffectedFiles(include_deletes=False):
Nicolas Penac4479c52017-06-26 11:45:06 -0400438 if not f.LocalPath().endswith('.png'):
439 continue
440 if expected_pattern.match(f.LocalPath()):
441 continue
442 results.append(output_api.PresubmitError(
443 'PNG file %s does not have the correct format' % f.LocalPath()))
444 return results
dsinclair2ca2da52016-09-13 18:10:34 -0700445
Lei Zhang624fba82021-06-15 20:11:39 +0000446
447def _CheckUselessForwardDeclarations(input_api, output_api):
448 """Checks that added or removed lines in non third party affected
449 header files do not lead to new useless class or struct forward
450 declaration.
451 """
452 results = []
453 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
454 input_api.re.MULTILINE)
455 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
456 input_api.re.MULTILINE)
457 for f in input_api.AffectedFiles(include_deletes=False):
458 if f.LocalPath().startswith('third_party'):
459 continue
460
461 if not f.LocalPath().endswith('.h'):
462 continue
463
464 contents = input_api.ReadFile(f)
465 fwd_decls = input_api.re.findall(class_pattern, contents)
466 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
467
468 useless_fwd_decls = []
469 for decl in fwd_decls:
470 count = sum(
471 1
472 for _ in input_api.re.finditer(r'\b%s\b' %
473 input_api.re.escape(decl), contents))
474 if count == 1:
475 useless_fwd_decls.append(decl)
476
477 if not useless_fwd_decls:
478 continue
479
480 for line in f.GenerateScmDiff().splitlines():
481 if (line.startswith('-') and not line.startswith('--') or
482 line.startswith('+') and not line.startswith('++')):
483 for decl in useless_fwd_decls:
484 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
485 results.append(
486 output_api.PresubmitPromptWarning(
487 '%s: %s forward declaration is no longer needed' %
488 (f.LocalPath(), decl)))
489 useless_fwd_decls.remove(decl)
490
491 return results
492
493
K. Moon5e33cbd2022-10-31 19:22:36 +0000494def ChecksCommon(input_api, output_api):
495 results = []
496
K. Moon5e33cbd2022-10-31 19:22:36 +0000497 results.extend(
498 input_api.canned_checks.PanProjectChecks(
K. Moon832a6942022-10-31 20:11:31 +0000499 input_api, output_api, project_name='PDFium'))
K. Moon5e33cbd2022-10-31 19:22:36 +0000500
K. Moon8636cff2022-11-02 18:45:43 +0000501 # PanProjectChecks() doesn't consider .gn/.gni files, so check those, too.
502 files_to_check = (
503 r'.*\.gn$',
504 r'.*\.gni$',
505 )
506 results.extend(
507 input_api.canned_checks.CheckLicense(
508 input_api,
509 output_api,
510 project_name='PDFium',
511 source_file_filter=lambda x: input_api.FilterSourceFile(
512 x, files_to_check=files_to_check)))
513
K. Moon5e33cbd2022-10-31 19:22:36 +0000514 return results
515
516
Nico Weber077f1a32015-08-06 15:08:57 -0700517def CheckChangeOnUpload(input_api, output_api):
518 results = []
Daniel Hosseinianb3bdbd42021-10-22 17:01:14 +0000519 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Lei Zhang804a0e32020-05-21 20:57:16 +0000520 results.extend(_CheckUnwantedDependencies(input_api, output_api))
521 results.extend(
522 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
523 results.extend(
Lei Zhang4c472552021-05-24 21:44:47 +0000524 input_api.canned_checks.CheckChangeLintsClean(
525 input_api, output_api, lint_filters=LINT_FILTERS))
Lei Zhang804a0e32020-05-21 20:57:16 +0000526 results.extend(_CheckIncludeOrder(input_api, output_api))
Lei Zhang07ef29a2022-09-10 06:52:25 +0000527 results.extend(_CheckLibcxxRevision(input_api, output_api))
Lei Zhang804a0e32020-05-21 20:57:16 +0000528 results.extend(_CheckTestDuplicates(input_api, output_api))
529 results.extend(_CheckPNGFormat(input_api, output_api))
Lei Zhang624fba82021-06-15 20:11:39 +0000530 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
Dan Sinclair544bbc62016-03-14 15:07:39 -0400531
Lei Zhang71e26732020-05-21 21:03:05 +0000532 author = input_api.change.author_email
533 if author and author not in _KNOWN_ROBOTS:
534 results.extend(
535 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
536
Hui Yingst2aa0a4a2020-04-09 19:04:21 +0000537 for f in input_api.AffectedFiles():
538 path, name = input_api.os_path.split(f.LocalPath())
539 if name == 'PRESUBMIT.py':
540 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
541 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
542 if f.Action() != 'D' and input_api.os_path.exists(test_file):
543 # The PRESUBMIT.py file (and the directory containing it) might
544 # have been affected by being moved or removed, so only try to
545 # run the tests if they still exist.
546 results.extend(
547 input_api.canned_checks.RunUnitTestsInDirectory(
548 input_api,
549 output_api,
550 full_path,
Lingqi Chied293672021-11-24 20:53:01 +0000551 files_to_check=[r'^PRESUBMIT_test\.py$'],
552 run_on_python2=not USE_PYTHON3,
553 run_on_python3=USE_PYTHON3,
554 skip_shebang_check=True))
Hui Yingst2aa0a4a2020-04-09 19:04:21 +0000555
Nico Weber077f1a32015-08-06 15:08:57 -0700556 return results