blob: fdbe15f9277d3e335955e31009730413b00fc3f3 [file] [log] [blame]
Avi Drissmanea1be232022-09-14 23:29:061# Copyright 2017 The Chromium Authors
Sylvain Defresnefcda19f2017-06-27 10:14:012# 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+$'
Petro Akzhygitovdb9b351622022-07-01 08:21:5018INCLUDE_PATTERN = r'^#include'
Gauthier Ambardf85c5f12022-09-14 11:26:5419PIPE_IN_COMMENT_PATTERN = r'//.*[^|]\|(?!\|)'
Petro Akzhygitovdb9b351622022-07-01 08:21:5020IOS_PACKAGE_PATTERN = r'^ios'
Gauthier Ambard7fc07bf2018-01-02 09:48:0921ARC_COMPILE_GUARD = [
22 '#if !defined(__has_feature) || !__has_feature(objc_arc)',
23 '#error "This file requires ARC support."',
24 '#endif',
25]
Louis Romeroe33c2da2023-01-19 14:18:5326BOXED_BOOL_PATTERN = r'@\((YES|NO)\)'
Gauthier Ambard7fc07bf2018-01-02 09:48:0927
28def IsSubListOf(needle, hay):
Gauthier Ambard1981d622022-09-13 09:34:4929 """Returns whether there is a slice of |hay| equal to |needle|."""
30 for i, line in enumerate(hay):
31 if line == needle[0]:
32 if needle == hay[i:i + len(needle)]:
33 return True
34 return False
35
[email protected]0066f732017-12-28 10:33:0836
37def _CheckARCCompilationGuard(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:4938 """ Checks whether new objc files have proper ARC compile guards."""
39 files_without_headers = []
40 for f in input_api.AffectedFiles():
41 if f.Action() != 'A':
42 continue
[email protected]0066f732017-12-28 10:33:0843
Gauthier Ambard1981d622022-09-13 09:34:4944 _, ext = os.path.splitext(f.LocalPath())
45 if ext not in ('.m', '.mm'):
46 continue
[email protected]0066f732017-12-28 10:33:0847
Gauthier Ambard1981d622022-09-13 09:34:4948 if not IsSubListOf(ARC_COMPILE_GUARD, f.NewContents()):
49 files_without_headers.append(f.LocalPath())
[email protected]0066f732017-12-28 10:33:0850
Gauthier Ambard1981d622022-09-13 09:34:4951 if not files_without_headers:
52 return []
[email protected]0066f732017-12-28 10:33:0853
Gauthier Ambard1981d622022-09-13 09:34:4954 plural_suffix = '' if len(files_without_headers) == 1 else 's'
55 error_message = '\n'.join([
56 'Found new Objective-C implementation file%(plural)s without compile'
57 ' guard%(plural)s. Please use the following compile guard'
58 ':' % {
59 'plural': plural_suffix
60 }
61 ] + ARC_COMPILE_GUARD + files_without_headers) + '\n'
[email protected]0066f732017-12-28 10:33:0862
Gauthier Ambard1981d622022-09-13 09:34:4963 return [output_api.PresubmitError(error_message)]
[email protected]0066f732017-12-28 10:33:0864
Sylvain Defresnefcda19f2017-06-27 10:14:0165
Nohemi Fernandeza3833372020-03-23 17:22:1966def _CheckNullabilityAnnotations(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:4967 """ Checks whether there are nullability annotations in ios code."""
68 nullability_regex = input_api.re.compile(NULLABILITY_PATTERN)
Sylvain Defresnefcda19f2017-06-27 10:14:0169
Gauthier Ambard1981d622022-09-13 09:34:4970 errors = []
71 for f in input_api.AffectedFiles():
72 for line_num, line in f.ChangedContents():
73 if nullability_regex.search(line):
74 errors.append('%s:%s' % (f.LocalPath(), line_num))
75 if not errors:
76 return []
Nohemi Fernandeza3833372020-03-23 17:22:1977
Gauthier Ambard1981d622022-09-13 09:34:4978 plural_suffix = '' if len(errors) == 1 else 's'
79 error_message = ('Found Nullability annotation%(plural)s. '
80 'Prefer DCHECKs in ios code to check for nullness:' % {
81 'plural': plural_suffix
82 })
Nohemi Fernandeza3833372020-03-23 17:22:1983
Gauthier Ambard1981d622022-09-13 09:34:4984 return [output_api.PresubmitPromptWarning(error_message, items=errors)]
Nohemi Fernandeza3833372020-03-23 17:22:1985
86
87def _CheckBugInToDo(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:4988 """ Checks whether TODOs in ios code are identified by a bug number."""
89 errors = []
90 for f in input_api.AffectedFiles():
91 for line_num, line in f.ChangedContents():
92 if _HasToDoWithNoBug(input_api, line):
93 errors.append('%s:%s' % (f.LocalPath(), line_num))
94 if not errors:
95 return []
Sylvain Defresnefcda19f2017-06-27 10:14:0196
Gauthier Ambard1981d622022-09-13 09:34:4997 plural_suffix = '' if len(errors) == 1 else 's'
98 error_message = '\n'.join([
99 'Found TO'
100 'DO%(plural)s without bug number%(plural)s (expected format '
101 'is \"TO'
102 'DO(crbug.com/######)\":' % {
103 'plural': plural_suffix
104 }
105 ] + errors) + '\n'
Sylvain Defresnefcda19f2017-06-27 10:14:01106
Gauthier Ambard1981d622022-09-13 09:34:49107 return [output_api.PresubmitError(error_message)]
Sylvain Defresnefcda19f2017-06-27 10:14:01108
109
Petro Akzhygitovdb9b351622022-07-01 08:21:50110def _CheckHasNoIncludeDirectives(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:49111 """ Checks that #include preprocessor directives are not present."""
112 errors = []
113 for f in input_api.AffectedFiles():
114 if not _IsInIosPackage(input_api, f.LocalPath()):
115 continue
116 _, ext = os.path.splitext(f.LocalPath())
117 if ext != '.mm':
118 continue
119 for line_num, line in f.ChangedContents():
120 if _HasIncludeDirective(input_api, line):
121 errors.append('%s:%s' % (f.LocalPath(), line_num))
122 if not errors:
123 return []
Petro Akzhygitovdb9b351622022-07-01 08:21:50124
Gauthier Ambard1981d622022-09-13 09:34:49125 singular_plural = 'it' if len(errors) == 1 else 'them'
126 plural_suffix = '' if len(errors) == 1 else 's'
127 error_message = '\n'.join([
128 'Found usage of `#include` preprocessor directive%(plural)s! Please, '
129 'replace %(singular_plural)s with `#import` preprocessor '
130 'directive%(plural)s instead. '
131 'Consider replacing all existing `#include` with `#import` (if any) in '
132 'this file for the code clean up. See '
133 'https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main'
134 '/styleguide/objective-c/objective-c.md'
135 '#import-and-include-in-the-directory for more details. '
136 '\n\nAffected file%(plural)s:' % {
137 'plural': plural_suffix,
138 'singular_plural': singular_plural
139 }
140 ] + errors) + '\n'
Petro Akzhygitovdb9b351622022-07-01 08:21:50141
Gauthier Ambard1981d622022-09-13 09:34:49142 return [output_api.PresubmitError(error_message)]
143
Petro Akzhygitovdb9b351622022-07-01 08:21:50144
Gauthier Ambardf85c5f12022-09-14 11:26:54145def _CheckHasNoPipeInComment(input_api, output_api):
146 """ Checks that comments don't contain pipes."""
147 pipe_regex = input_api.re.compile(PIPE_IN_COMMENT_PATTERN)
148
149 errors = []
150 for f in input_api.AffectedFiles():
151 if not _IsInIosPackage(input_api, f.LocalPath()):
152 continue
153 for line_num, line in f.ChangedContents():
154 if pipe_regex.search(line):
155 errors.append('%s:%s' % (f.LocalPath(), line_num))
156 if not errors:
157 return []
158 error_message = '\n'.join([
159 'Please use backticks "`" instead of pipes "|" if you need to quote'
160 ' variable names and symbols in comments.\n'
161 'Found potential uses of pipes in:'
162 ] + errors) + '\n'
163
164 return [output_api.PresubmitPromptWarning(error_message)]
165
166
Petro Akzhygitovdb9b351622022-07-01 08:21:50167def _IsInIosPackage(input_api, path):
Gauthier Ambard1981d622022-09-13 09:34:49168 """ Returns True if path is within ios package"""
169 ios_package_regex = input_api.re.compile(IOS_PACKAGE_PATTERN)
Petro Akzhygitovdb9b351622022-07-01 08:21:50170
Gauthier Ambard1981d622022-09-13 09:34:49171 return ios_package_regex.search(path)
172
Petro Akzhygitovdb9b351622022-07-01 08:21:50173
174def _HasIncludeDirective(input_api, line):
Gauthier Ambard1981d622022-09-13 09:34:49175 """ Returns True if #include is found in the line"""
176 include_regex = input_api.re.compile(INCLUDE_PATTERN)
Petro Akzhygitovdb9b351622022-07-01 08:21:50177
Gauthier Ambard1981d622022-09-13 09:34:49178 return include_regex.search(line)
179
Petro Akzhygitovdb9b351622022-07-01 08:21:50180
Nohemi Fernandeza3833372020-03-23 17:22:19181def _HasToDoWithNoBug(input_api, line):
Gauthier Ambard1981d622022-09-13 09:34:49182 """ Returns True if TODO is not identified by a bug number."""
183 todo_regex = input_api.re.compile(TODO_PATTERN)
184 crbug_regex = input_api.re.compile(CRBUG_PATTERN)
Nohemi Fernandeza3833372020-03-23 17:22:19185
Gauthier Ambard1981d622022-09-13 09:34:49186 todo_match = todo_regex.search(line)
187 if not todo_match:
188 return False
189 crbug_match = crbug_regex.match(todo_match.group(1))
190 return not crbug_match
Nohemi Fernandeza3833372020-03-23 17:22:19191
Louis Romeroe33c2da2023-01-19 14:18:53192def _CheckHasNoBoxedBOOL(input_api, output_api):
193 """ Checks that there are no @(YES) or @(NO)."""
194 boxed_BOOL_regex = input_api.re.compile(BOXED_BOOL_PATTERN)
195
196 errors = []
197 for f in input_api.AffectedFiles():
198 for line_num, line in f.ChangedContents():
199 if boxed_BOOL_regex.search(line):
200 errors.append('%s:%s' % (f.LocalPath(), line_num))
201 if not errors:
202 return []
203
204 plural_suffix = '' if len(errors) == 1 else 's'
205 error_message = ('Found boxed BOOL%(plural)s. '
206 'Prefer @YES or @NO in ios code:' % {
207 'plural': plural_suffix
208 })
209
210 return [output_api.PresubmitPromptWarning(error_message, items=errors)]
Nohemi Fernandeza3833372020-03-23 17:22:19211
Sylvain Defresnefcda19f2017-06-27 10:14:01212def CheckChangeOnUpload(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:49213 results = []
214 results.extend(_CheckBugInToDo(input_api, output_api))
215 results.extend(_CheckNullabilityAnnotations(input_api, output_api))
216 results.extend(_CheckARCCompilationGuard(input_api, output_api))
217 results.extend(_CheckHasNoIncludeDirectives(input_api, output_api))
Gauthier Ambardf85c5f12022-09-14 11:26:54218 results.extend(_CheckHasNoPipeInComment(input_api, output_api))
Louis Romeroe33c2da2023-01-19 14:18:53219 results.extend(_CheckHasNoBoxedBOOL(input_api, output_api))
Gauthier Ambard1981d622022-09-13 09:34:49220 return results