Revert of [builtins] Unify the various versions of [[Call]] with a Call builtin....
[platform/upstream/v8.git] / PRESUBMIT.py
1 # Copyright 2012 the V8 project authors. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are
4 # met:
5 #
6 #     * Redistributions of source code must retain the above copyright
7 #       notice, this list of conditions and the following disclaimer.
8 #     * Redistributions in binary form must reproduce the above
9 #       copyright notice, this list of conditions and the following
10 #       disclaimer in the documentation and/or other materials provided
11 #       with the distribution.
12 #     * Neither the name of Google Inc. nor the names of its
13 #       contributors may be used to endorse or promote products derived
14 #       from this software without specific prior written permission.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 """Top-level presubmit script for V8.
29
30 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
31 for more details about the presubmit API built into gcl.
32 """
33
34 import sys
35
36
37 _EXCLUDED_PATHS = (
38     r"^test[\\\/].*",
39     r"^testing[\\\/].*",
40     r"^third_party[\\\/].*",
41     r"^tools[\\\/].*",
42 )
43
44
45 # Regular expression that matches code only used for test binaries
46 # (best effort).
47 _TEST_CODE_EXCLUDED_PATHS = (
48     r'.+-unittest\.cc',
49     # Has a method VisitForTest().
50     r'src[\\\/]compiler[\\\/]ast-graph-builder\.cc',
51     # Test extension.
52     r'src[\\\/]extensions[\\\/]gc-extension\.cc',
53 )
54
55
56 _TEST_ONLY_WARNING = (
57     'You might be calling functions intended only for testing from\n'
58     'production code.  It is OK to ignore this warning if you know what\n'
59     'you are doing, as the heuristics used to detect the situation are\n'
60     'not perfect.  The commit queue will not block on this warning.')
61
62
63 def _V8PresubmitChecks(input_api, output_api):
64   """Runs the V8 presubmit checks."""
65   import sys
66   sys.path.append(input_api.os_path.join(
67         input_api.PresubmitLocalPath(), 'tools'))
68   from presubmit import CppLintProcessor
69   from presubmit import SourceProcessor
70   from presubmit import CheckExternalReferenceRegistration
71   from presubmit import CheckAuthorizedAuthor
72
73   results = []
74   if not CppLintProcessor().Run(input_api.PresubmitLocalPath()):
75     results.append(output_api.PresubmitError("C++ lint check failed"))
76   if not SourceProcessor().Run(input_api.PresubmitLocalPath()):
77     results.append(output_api.PresubmitError(
78         "Copyright header, trailing whitespaces and two empty lines " \
79         "between declarations check failed"))
80   if not CheckExternalReferenceRegistration(input_api.PresubmitLocalPath()):
81     results.append(output_api.PresubmitError(
82         "External references registration check failed"))
83   results.extend(CheckAuthorizedAuthor(input_api, output_api))
84   return results
85
86
87 def _CheckUnwantedDependencies(input_api, output_api):
88   """Runs checkdeps on #include statements added in this
89   change. Breaking - rules is an error, breaking ! rules is a
90   warning.
91   """
92   # We need to wait until we have an input_api object and use this
93   # roundabout construct to import checkdeps because this file is
94   # eval-ed and thus doesn't have __file__.
95   original_sys_path = sys.path
96   try:
97     sys.path = sys.path + [input_api.os_path.join(
98         input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
99     import checkdeps
100     from cpp_checker import CppChecker
101     from rules import Rule
102   finally:
103     # Restore sys.path to what it was before.
104     sys.path = original_sys_path
105
106   added_includes = []
107   for f in input_api.AffectedFiles():
108     if not CppChecker.IsCppFile(f.LocalPath()):
109       continue
110
111     changed_lines = [line for line_num, line in f.ChangedContents()]
112     added_includes.append([f.LocalPath(), changed_lines])
113
114   deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
115
116   error_descriptions = []
117   warning_descriptions = []
118   for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
119       added_includes):
120     description_with_path = '%s\n    %s' % (path, rule_description)
121     if rule_type == Rule.DISALLOW:
122       error_descriptions.append(description_with_path)
123     else:
124       warning_descriptions.append(description_with_path)
125
126   results = []
127   if error_descriptions:
128     results.append(output_api.PresubmitError(
129         'You added one or more #includes that violate checkdeps rules.',
130         error_descriptions))
131   if warning_descriptions:
132     results.append(output_api.PresubmitPromptOrNotify(
133         'You added one or more #includes of files that are temporarily\n'
134         'allowed but being removed. Can you avoid introducing the\n'
135         '#include? See relevant DEPS file(s) for details and contacts.',
136         warning_descriptions))
137   return results
138
139
140 def _CheckNoInlineHeaderIncludesInNormalHeaders(input_api, output_api):
141   """Attempts to prevent inclusion of inline headers into normal header
142   files. This tries to establish a layering where inline headers can be
143   included by other inline headers or compilation units only."""
144   file_inclusion_pattern = r'(?!.+-inl\.h).+\.h'
145   include_directive_pattern = input_api.re.compile(r'#include ".+-inl.h"')
146   include_warning = (
147     'You might be including an inline header (e.g. foo-inl.h) within a\n'
148     'normal header (e.g. bar.h) file.  Can you avoid introducing the\n'
149     '#include?  The commit queue will not block on this warning.')
150
151   def FilterFile(affected_file):
152     black_list = (_EXCLUDED_PATHS +
153                   input_api.DEFAULT_BLACK_LIST)
154     return input_api.FilterSourceFile(
155       affected_file,
156       white_list=(file_inclusion_pattern, ),
157       black_list=black_list)
158
159   problems = []
160   for f in input_api.AffectedSourceFiles(FilterFile):
161     local_path = f.LocalPath()
162     for line_number, line in f.ChangedContents():
163       if (include_directive_pattern.search(line)):
164         problems.append(
165           '%s:%d\n    %s' % (local_path, line_number, line.strip()))
166
167   if problems:
168     return [output_api.PresubmitPromptOrNotify(include_warning, problems)]
169   else:
170     return []
171
172
173 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
174   """Attempts to prevent use of functions intended only for testing in
175   non-testing code. For now this is just a best-effort implementation
176   that ignores header files and may have some false positives. A
177   better implementation would probably need a proper C++ parser.
178   """
179   # We only scan .cc files, as the declaration of for-testing functions in
180   # header files are hard to distinguish from calls to such functions without a
181   # proper C++ parser.
182   file_inclusion_pattern = r'.+\.cc'
183
184   base_function_pattern = r'[ :]test::[^\s]+|ForTest(ing)?|for_test(ing)?'
185   inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
186   comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
187   exclusion_pattern = input_api.re.compile(
188     r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
189       base_function_pattern, base_function_pattern))
190
191   def FilterFile(affected_file):
192     black_list = (_EXCLUDED_PATHS +
193                   _TEST_CODE_EXCLUDED_PATHS +
194                   input_api.DEFAULT_BLACK_LIST)
195     return input_api.FilterSourceFile(
196       affected_file,
197       white_list=(file_inclusion_pattern, ),
198       black_list=black_list)
199
200   problems = []
201   for f in input_api.AffectedSourceFiles(FilterFile):
202     local_path = f.LocalPath()
203     for line_number, line in f.ChangedContents():
204       if (inclusion_pattern.search(line) and
205           not comment_pattern.search(line) and
206           not exclusion_pattern.search(line)):
207         problems.append(
208           '%s:%d\n    %s' % (local_path, line_number, line.strip()))
209
210   if problems:
211     return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
212   else:
213     return []
214
215
216 def _CommonChecks(input_api, output_api):
217   """Checks common to both upload and commit."""
218   results = []
219   results.extend(input_api.canned_checks.CheckOwners(
220       input_api, output_api, source_file_filter=None))
221   results.extend(input_api.canned_checks.CheckPatchFormatted(
222       input_api, output_api))
223   results.extend(_V8PresubmitChecks(input_api, output_api))
224   results.extend(_CheckUnwantedDependencies(input_api, output_api))
225   results.extend(
226       _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
227   results.extend(
228       _CheckNoInlineHeaderIncludesInNormalHeaders(input_api, output_api))
229   return results
230
231
232 def _SkipTreeCheck(input_api, output_api):
233   """Check the env var whether we want to skip tree check.
234      Only skip if include/v8-version.h has been updated."""
235   src_version = 'include/v8-version.h'
236   FilterFile = lambda file: file.LocalPath() == src_version
237   if not input_api.AffectedSourceFiles(
238       lambda file: file.LocalPath() == src_version):
239     return False
240   return input_api.environ.get('PRESUBMIT_TREE_CHECK') == 'skip'
241
242
243 def _CheckChangeLogFlag(input_api, output_api, warn):
244   """Checks usage of LOG= flag in the commit message."""
245   results = []
246   if (input_api.change.BUG and input_api.change.BUG != 'none' and
247       not 'LOG' in input_api.change.tags):
248     text = ('An issue reference (BUG=) requires a change log flag (LOG=). '
249             'Use LOG=Y for including this commit message in the change log. '
250             'Use LOG=N or leave blank otherwise.')
251     if warn:
252       results.append(output_api.PresubmitPromptWarning(text))
253     else:
254       results.append(output_api.PresubmitError(text))
255   return results
256
257
258 def CheckChangeOnUpload(input_api, output_api):
259   results = []
260   results.extend(_CommonChecks(input_api, output_api))
261   results.extend(_CheckChangeLogFlag(input_api, output_api, True))
262   return results
263
264
265 def CheckChangeOnCommit(input_api, output_api):
266   results = []
267   results.extend(_CommonChecks(input_api, output_api))
268   results.extend(_CheckChangeLogFlag(input_api, output_api, False))
269   results.extend(input_api.canned_checks.CheckChangeHasDescription(
270       input_api, output_api))
271   if not _SkipTreeCheck(input_api, output_api):
272     results.extend(input_api.canned_checks.CheckTreeIsOpen(
273         input_api, output_api,
274         json_url='http://v8-status.appspot.com/current?format=json'))
275   return results
276
277
278 def GetPreferredTryMasters(project, change):
279   return {
280     'tryserver.v8': {
281       'v8_linux_rel': set(['defaulttests']),
282       'v8_linux_dbg': set(['defaulttests']),
283       'v8_linux_nodcheck_rel': set(['defaulttests']),
284       'v8_linux_gcc_compile_rel': set(['defaulttests']),
285       'v8_linux64_rel': set(['defaulttests']),
286       'v8_linux64_asan_rel': set(['defaulttests']),
287       'v8_linux64_avx2_rel': set(['defaulttests']),
288       'v8_win_rel': set(['defaulttests']),
289       'v8_win_compile_dbg': set(['defaulttests']),
290       'v8_win_nosnap_shared_compile_rel': set(['defaulttests']),
291       'v8_win64_rel': set(['defaulttests']),
292       'v8_mac_rel': set(['defaulttests']),
293       'v8_linux_arm_rel': set(['defaulttests']),
294       'v8_linux_arm64_rel': set(['defaulttests']),
295       'v8_linux_mipsel_compile_rel': set(['defaulttests']),
296       'v8_linux_mips64el_compile_rel': set(['defaulttests']),
297       'v8_android_arm_compile_rel': set(['defaulttests']),
298       'v8_linux_chromium_gn_rel': set(['defaulttests']),
299     },
300   }