blob: 6c76d51ea27f86c2097e048d24d2bb4771e18345 [file] [log] [blame]
Sylvain Defresnefcda19f2017-06-27 10:14:011# Copyright 2017 The Chromium Authors. All rights reserved.
2# 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 ios.
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
[email protected]0066f732017-12-28 10:33:0811import os
12
Josip Sokcevic2e6b82bd2021-06-14 09:37:3113USE_PYTHON3 = True
14
Nohemi Fernandeza3833372020-03-23 17:22:1915NULLABILITY_PATTERN = r'(nonnull|nullable|_Nullable|_Nonnull)'
Sylvain Defresnefcda19f2017-06-27 10:14:0116TODO_PATTERN = r'TO[D]O\(([^\)]*)\)'
17CRBUG_PATTERN = r'crbug\.com/\d+$'
Gauthier Ambard7fc07bf2018-01-02 09:48:0918ARC_COMPILE_GUARD = [
19 '#if !defined(__has_feature) || !__has_feature(objc_arc)',
20 '#error "This file requires ARC support."',
21 '#endif',
22]
23
24def IsSubListOf(needle, hay):
25 """Returns whether there is a slice of |hay| equal to |needle|."""
26 for i, line in enumerate(hay):
27 if line == needle[0]:
28 if needle == hay[i:i+len(needle)]:
29 return True
30 return False
[email protected]0066f732017-12-28 10:33:0831
32def _CheckARCCompilationGuard(input_api, output_api):
33 """ Checks whether new objc files have proper ARC compile guards."""
34 files_without_headers = []
35 for f in input_api.AffectedFiles():
36 if f.Action() != 'A':
37 continue
38
39 _, ext = os.path.splitext(f.LocalPath())
40 if ext not in ('.m', '.mm'):
41 continue
42
Gauthier Ambard7fc07bf2018-01-02 09:48:0943 if not IsSubListOf(ARC_COMPILE_GUARD, f.NewContents()):
44 files_without_headers.append(f.LocalPath())
[email protected]0066f732017-12-28 10:33:0845
46 if not files_without_headers:
47 return []
48
49 plural_suffix = '' if len(files_without_headers) == 1 else 's'
50 error_message = '\n'.join([
51 'Found new Objective-C implementation file%(plural)s without compile'
52 ' guard%(plural)s. Please use the following compile guard'
Gauthier Ambard7fc07bf2018-01-02 09:48:0953 ':' % {'plural': plural_suffix}
54 ] + ARC_COMPILE_GUARD + files_without_headers) + '\n'
[email protected]0066f732017-12-28 10:33:0855
56 return [output_api.PresubmitError(error_message)]
57
Sylvain Defresnefcda19f2017-06-27 10:14:0158
Nohemi Fernandeza3833372020-03-23 17:22:1959def _CheckNullabilityAnnotations(input_api, output_api):
60 """ Checks whether there are nullability annotations in ios code."""
61 nullability_regex = input_api.re.compile(NULLABILITY_PATTERN)
Sylvain Defresnefcda19f2017-06-27 10:14:0162
63 errors = []
64 for f in input_api.AffectedFiles():
65 for line_num, line in f.ChangedContents():
Nohemi Fernandeza3833372020-03-23 17:22:1966 if nullability_regex.search(line):
67 errors.append('%s:%s' % (f.LocalPath(), line_num))
68 if not errors:
69 return []
70
71 plural_suffix = '' if len(errors) == 1 else 's'
72 error_message = ('Found Nullability annotation%(plural)s. '
73 'Prefer DCHECKs in ios code to check for nullness:'
74 % {'plural': plural_suffix})
75
76 return [output_api.PresubmitPromptWarning(error_message, items=errors)]
77
78
79def _CheckBugInToDo(input_api, output_api):
80 """ Checks whether TODOs in ios code are identified by a bug number."""
81 errors = []
82 for f in input_api.AffectedFiles():
83 for line_num, line in f.ChangedContents():
84 if _HasToDoWithNoBug(input_api, line):
Sylvain Defresnefcda19f2017-06-27 10:14:0185 errors.append('%s:%s' % (f.LocalPath(), line_num))
86 if not errors:
87 return []
88
89 plural_suffix = '' if len(errors) == 1 else 's'
90 error_message = '\n'.join([
91 'Found TO''DO%(plural)s without bug number%(plural)s (expected format is '
92 '\"TO''DO(crbug.com/######)\":' % {'plural': plural_suffix}
93 ] + errors) + '\n'
94
95 return [output_api.PresubmitError(error_message)]
96
97
Nohemi Fernandeza3833372020-03-23 17:22:1998def _HasToDoWithNoBug(input_api, line):
99 """ Returns True if TODO is not identified by a bug number."""
100 todo_regex = input_api.re.compile(TODO_PATTERN)
101 crbug_regex = input_api.re.compile(CRBUG_PATTERN)
102
103 todo_match = todo_regex.search(line)
104 if not todo_match:
105 return False
106 crbug_match = crbug_regex.match(todo_match.group(1))
107 return not crbug_match
108
109
Sylvain Defresnefcda19f2017-06-27 10:14:01110def CheckChangeOnUpload(input_api, output_api):
111 results = []
112 results.extend(_CheckBugInToDo(input_api, output_api))
Nohemi Fernandeza3833372020-03-23 17:22:19113 results.extend(_CheckNullabilityAnnotations(input_api, output_api))
[email protected]0066f732017-12-28 10:33:08114 results.extend(_CheckARCCompilationGuard(input_api, output_api))
Sylvain Defresnefcda19f2017-06-27 10:14:01115 return results