blob: 8fdaae9bc9deb16cf8526e15f70f5837cceb58f7 [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
Nohemi Fernandeza3833372020-03-23 17:22:1913NULLABILITY_PATTERN = r'(nonnull|nullable|_Nullable|_Nonnull)'
Sylvain Defresnefcda19f2017-06-27 10:14:0114TODO_PATTERN = r'TO[D]O\(([^\)]*)\)'
15CRBUG_PATTERN = r'crbug\.com/\d+$'
Gauthier Ambard7fc07bf2018-01-02 09:48:0916ARC_COMPILE_GUARD = [
17 '#if !defined(__has_feature) || !__has_feature(objc_arc)',
18 '#error "This file requires ARC support."',
19 '#endif',
20]
21
22def IsSubListOf(needle, hay):
23 """Returns whether there is a slice of |hay| equal to |needle|."""
24 for i, line in enumerate(hay):
25 if line == needle[0]:
26 if needle == hay[i:i+len(needle)]:
27 return True
28 return False
[email protected]0066f732017-12-28 10:33:0829
30def _CheckARCCompilationGuard(input_api, output_api):
31 """ Checks whether new objc files have proper ARC compile guards."""
32 files_without_headers = []
33 for f in input_api.AffectedFiles():
34 if f.Action() != 'A':
35 continue
36
37 _, ext = os.path.splitext(f.LocalPath())
38 if ext not in ('.m', '.mm'):
39 continue
40
Gauthier Ambard7fc07bf2018-01-02 09:48:0941 if not IsSubListOf(ARC_COMPILE_GUARD, f.NewContents()):
42 files_without_headers.append(f.LocalPath())
[email protected]0066f732017-12-28 10:33:0843
44 if not files_without_headers:
45 return []
46
47 plural_suffix = '' if len(files_without_headers) == 1 else 's'
48 error_message = '\n'.join([
49 'Found new Objective-C implementation file%(plural)s without compile'
50 ' guard%(plural)s. Please use the following compile guard'
Gauthier Ambard7fc07bf2018-01-02 09:48:0951 ':' % {'plural': plural_suffix}
52 ] + ARC_COMPILE_GUARD + files_without_headers) + '\n'
[email protected]0066f732017-12-28 10:33:0853
54 return [output_api.PresubmitError(error_message)]
55
Sylvain Defresnefcda19f2017-06-27 10:14:0156
Nohemi Fernandeza3833372020-03-23 17:22:1957def _CheckNullabilityAnnotations(input_api, output_api):
58 """ Checks whether there are nullability annotations in ios code."""
59 nullability_regex = input_api.re.compile(NULLABILITY_PATTERN)
Sylvain Defresnefcda19f2017-06-27 10:14:0160
61 errors = []
62 for f in input_api.AffectedFiles():
63 for line_num, line in f.ChangedContents():
Nohemi Fernandeza3833372020-03-23 17:22:1964 if nullability_regex.search(line):
65 errors.append('%s:%s' % (f.LocalPath(), line_num))
66 if not errors:
67 return []
68
69 plural_suffix = '' if len(errors) == 1 else 's'
70 error_message = ('Found Nullability annotation%(plural)s. '
71 'Prefer DCHECKs in ios code to check for nullness:'
72 % {'plural': plural_suffix})
73
74 return [output_api.PresubmitPromptWarning(error_message, items=errors)]
75
76
77def _CheckBugInToDo(input_api, output_api):
78 """ Checks whether TODOs in ios code are identified by a bug number."""
79 errors = []
80 for f in input_api.AffectedFiles():
81 for line_num, line in f.ChangedContents():
82 if _HasToDoWithNoBug(input_api, line):
Sylvain Defresnefcda19f2017-06-27 10:14:0183 errors.append('%s:%s' % (f.LocalPath(), line_num))
84 if not errors:
85 return []
86
87 plural_suffix = '' if len(errors) == 1 else 's'
88 error_message = '\n'.join([
89 'Found TO''DO%(plural)s without bug number%(plural)s (expected format is '
90 '\"TO''DO(crbug.com/######)\":' % {'plural': plural_suffix}
91 ] + errors) + '\n'
92
93 return [output_api.PresubmitError(error_message)]
94
95
Nohemi Fernandeza3833372020-03-23 17:22:1996def _HasToDoWithNoBug(input_api, line):
97 """ Returns True if TODO is not identified by a bug number."""
98 todo_regex = input_api.re.compile(TODO_PATTERN)
99 crbug_regex = input_api.re.compile(CRBUG_PATTERN)
100
101 todo_match = todo_regex.search(line)
102 if not todo_match:
103 return False
104 crbug_match = crbug_regex.match(todo_match.group(1))
105 return not crbug_match
106
107
Sylvain Defresnefcda19f2017-06-27 10:14:01108def CheckChangeOnUpload(input_api, output_api):
109 results = []
110 results.extend(_CheckBugInToDo(input_api, output_api))
Nohemi Fernandeza3833372020-03-23 17:22:19111 results.extend(_CheckNullabilityAnnotations(input_api, output_api))
[email protected]0066f732017-12-28 10:33:08112 results.extend(_CheckARCCompilationGuard(input_api, output_api))
Sylvain Defresnefcda19f2017-06-27 10:14:01113 return results