xref: /aosp_15_r20/external/webrtc/PRESUBMIT.py (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker#!/usr/bin/env vpython3
2*d9f75844SAndroid Build Coastguard Worker
3*d9f75844SAndroid Build Coastguard Worker# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4*d9f75844SAndroid Build Coastguard Worker#
5*d9f75844SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license
6*d9f75844SAndroid Build Coastguard Worker# that can be found in the LICENSE file in the root of the source
7*d9f75844SAndroid Build Coastguard Worker# tree. An additional intellectual property rights grant can be found
8*d9f75844SAndroid Build Coastguard Worker# in the file PATENTS.  All contributing project authors may
9*d9f75844SAndroid Build Coastguard Worker# be found in the AUTHORS file in the root of the source tree.
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Workerimport json
12*d9f75844SAndroid Build Coastguard Workerimport os
13*d9f75844SAndroid Build Coastguard Workerimport re
14*d9f75844SAndroid Build Coastguard Workerimport sys
15*d9f75844SAndroid Build Coastguard Workerfrom collections import defaultdict
16*d9f75844SAndroid Build Coastguard Workerfrom contextlib import contextmanager
17*d9f75844SAndroid Build Coastguard Worker
18*d9f75844SAndroid Build Coastguard Worker# Runs PRESUBMIT.py in py3 mode by git cl presubmit.
19*d9f75844SAndroid Build Coastguard WorkerUSE_PYTHON3 = True
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker# Files and directories that are *skipped* by cpplint in the presubmit script.
22*d9f75844SAndroid Build Coastguard WorkerCPPLINT_EXCEPTIONS = [
23*d9f75844SAndroid Build Coastguard Worker    'api/video_codecs/video_decoder.h',
24*d9f75844SAndroid Build Coastguard Worker    'common_types.cc',
25*d9f75844SAndroid Build Coastguard Worker    'common_types.h',
26*d9f75844SAndroid Build Coastguard Worker    'examples/objc',
27*d9f75844SAndroid Build Coastguard Worker    'media/base/stream_params.h',
28*d9f75844SAndroid Build Coastguard Worker    'media/base/video_common.h',
29*d9f75844SAndroid Build Coastguard Worker    'modules/audio_coding',
30*d9f75844SAndroid Build Coastguard Worker    'modules/audio_device',
31*d9f75844SAndroid Build Coastguard Worker    'modules/audio_processing',
32*d9f75844SAndroid Build Coastguard Worker    'modules/desktop_capture',
33*d9f75844SAndroid Build Coastguard Worker    'modules/include/module_common_types.h',
34*d9f75844SAndroid Build Coastguard Worker    'modules/utility',
35*d9f75844SAndroid Build Coastguard Worker    'modules/video_capture',
36*d9f75844SAndroid Build Coastguard Worker    'p2p/base/pseudo_tcp.cc',
37*d9f75844SAndroid Build Coastguard Worker    'p2p/base/pseudo_tcp.h',
38*d9f75844SAndroid Build Coastguard Worker    'PRESUBMIT.py',
39*d9f75844SAndroid Build Coastguard Worker    'presubmit_test_mocks.py',
40*d9f75844SAndroid Build Coastguard Worker    'presubmit_test.py',
41*d9f75844SAndroid Build Coastguard Worker    'rtc_base',
42*d9f75844SAndroid Build Coastguard Worker    'sdk/android/src/jni',
43*d9f75844SAndroid Build Coastguard Worker    'sdk/objc',
44*d9f75844SAndroid Build Coastguard Worker    'system_wrappers',
45*d9f75844SAndroid Build Coastguard Worker    'test',
46*d9f75844SAndroid Build Coastguard Worker    'tools_webrtc',
47*d9f75844SAndroid Build Coastguard Worker    'voice_engine',
48*d9f75844SAndroid Build Coastguard Worker]
49*d9f75844SAndroid Build Coastguard Worker
50*d9f75844SAndroid Build Coastguard Worker# These filters will always be removed, even if the caller specifies a filter
51*d9f75844SAndroid Build Coastguard Worker# set, as they are problematic or broken in some way.
52*d9f75844SAndroid Build Coastguard Worker#
53*d9f75844SAndroid Build Coastguard Worker# Justifications for each filter:
54*d9f75844SAndroid Build Coastguard Worker# - build/c++11         : Rvalue ref checks are unreliable (false positives),
55*d9f75844SAndroid Build Coastguard Worker#                         include file and feature blocklists are
56*d9f75844SAndroid Build Coastguard Worker#                         google3-specific.
57*d9f75844SAndroid Build Coastguard Worker# - runtime/references  : Mutable references are not banned by the Google
58*d9f75844SAndroid Build Coastguard Worker#                         C++ style guide anymore (starting from May 2020).
59*d9f75844SAndroid Build Coastguard Worker# - whitespace/operators: Same as above (doesn't seem sufficient to eliminate
60*d9f75844SAndroid Build Coastguard Worker#                         all move-related errors).
61*d9f75844SAndroid Build Coastguard WorkerDISABLED_LINT_FILTERS = [
62*d9f75844SAndroid Build Coastguard Worker    '-build/c++11',
63*d9f75844SAndroid Build Coastguard Worker    '-runtime/references',
64*d9f75844SAndroid Build Coastguard Worker    '-whitespace/operators',
65*d9f75844SAndroid Build Coastguard Worker]
66*d9f75844SAndroid Build Coastguard Worker
67*d9f75844SAndroid Build Coastguard Worker# List of directories of "supported" native APIs. That means changes to headers
68*d9f75844SAndroid Build Coastguard Worker# will be done in a compatible way following this scheme:
69*d9f75844SAndroid Build Coastguard Worker# 1. Non-breaking changes are made.
70*d9f75844SAndroid Build Coastguard Worker# 2. The old APIs as marked as deprecated (with comments).
71*d9f75844SAndroid Build Coastguard Worker# 3. Deprecation is announced to [email protected] and
72*d9f75844SAndroid Build Coastguard Worker#    [email protected] (internal list).
73*d9f75844SAndroid Build Coastguard Worker# 4. (later) The deprecated APIs are removed.
74*d9f75844SAndroid Build Coastguard WorkerNATIVE_API_DIRS = (
75*d9f75844SAndroid Build Coastguard Worker    'api',  # All subdirectories of api/ are included as well.
76*d9f75844SAndroid Build Coastguard Worker    'media/base',
77*d9f75844SAndroid Build Coastguard Worker    'media/engine',
78*d9f75844SAndroid Build Coastguard Worker    'modules/audio_device/include',
79*d9f75844SAndroid Build Coastguard Worker    'pc',
80*d9f75844SAndroid Build Coastguard Worker)
81*d9f75844SAndroid Build Coastguard Worker
82*d9f75844SAndroid Build Coastguard Worker# These directories should not be used but are maintained only to avoid breaking
83*d9f75844SAndroid Build Coastguard Worker# some legacy downstream code.
84*d9f75844SAndroid Build Coastguard WorkerLEGACY_API_DIRS = (
85*d9f75844SAndroid Build Coastguard Worker    'common_audio/include',
86*d9f75844SAndroid Build Coastguard Worker    'modules/audio_coding/include',
87*d9f75844SAndroid Build Coastguard Worker    'modules/audio_processing/include',
88*d9f75844SAndroid Build Coastguard Worker    'modules/congestion_controller/include',
89*d9f75844SAndroid Build Coastguard Worker    'modules/include',
90*d9f75844SAndroid Build Coastguard Worker    'modules/remote_bitrate_estimator/include',
91*d9f75844SAndroid Build Coastguard Worker    'modules/rtp_rtcp/include',
92*d9f75844SAndroid Build Coastguard Worker    'modules/rtp_rtcp/source',
93*d9f75844SAndroid Build Coastguard Worker    'modules/utility/include',
94*d9f75844SAndroid Build Coastguard Worker    'modules/video_coding/codecs/h264/include',
95*d9f75844SAndroid Build Coastguard Worker    'modules/video_coding/codecs/vp8/include',
96*d9f75844SAndroid Build Coastguard Worker    'modules/video_coding/codecs/vp9/include',
97*d9f75844SAndroid Build Coastguard Worker    'modules/video_coding/include',
98*d9f75844SAndroid Build Coastguard Worker    'rtc_base',
99*d9f75844SAndroid Build Coastguard Worker    'system_wrappers/include',
100*d9f75844SAndroid Build Coastguard Worker)
101*d9f75844SAndroid Build Coastguard Worker
102*d9f75844SAndroid Build Coastguard Worker# NOTE: The set of directories in API_DIRS should be the same as those
103*d9f75844SAndroid Build Coastguard Worker# listed in the table in native-api.md.
104*d9f75844SAndroid Build Coastguard WorkerAPI_DIRS = NATIVE_API_DIRS[:] + LEGACY_API_DIRS[:]
105*d9f75844SAndroid Build Coastguard Worker
106*d9f75844SAndroid Build Coastguard Worker# TARGET_RE matches a GN target, and extracts the target name and the contents.
107*d9f75844SAndroid Build Coastguard WorkerTARGET_RE = re.compile(
108*d9f75844SAndroid Build Coastguard Worker    r'(?P<indent>\s*)(?P<target_type>\w+)\("(?P<target_name>\w+)"\) {'
109*d9f75844SAndroid Build Coastguard Worker    r'(?P<target_contents>.*?)'
110*d9f75844SAndroid Build Coastguard Worker    r'(?P=indent)}', re.MULTILINE | re.DOTALL)
111*d9f75844SAndroid Build Coastguard Worker
112*d9f75844SAndroid Build Coastguard Worker# SOURCES_RE matches a block of sources inside a GN target.
113*d9f75844SAndroid Build Coastguard WorkerSOURCES_RE = re.compile(r'sources \+?= \[(?P<sources>.*?)\]',
114*d9f75844SAndroid Build Coastguard Worker                        re.MULTILINE | re.DOTALL)
115*d9f75844SAndroid Build Coastguard Worker
116*d9f75844SAndroid Build Coastguard Worker# DEPS_RE matches a block of sources inside a GN target.
117*d9f75844SAndroid Build Coastguard WorkerDEPS_RE = re.compile(r'\bdeps \+?= \[(?P<deps>.*?)\]',
118*d9f75844SAndroid Build Coastguard Worker                     re.MULTILINE | re.DOTALL)
119*d9f75844SAndroid Build Coastguard Worker
120*d9f75844SAndroid Build Coastguard Worker# FILE_PATH_RE matches a file path.
121*d9f75844SAndroid Build Coastguard WorkerFILE_PATH_RE = re.compile(r'"(?P<file_path>(\w|\/)+)(?P<extension>\.\w+)"')
122*d9f75844SAndroid Build Coastguard Worker
123*d9f75844SAndroid Build Coastguard Worker
124*d9f75844SAndroid Build Coastguard Workerdef FindSrcDirPath(starting_dir):
125*d9f75844SAndroid Build Coastguard Worker  """Returns the abs path to the src/ dir of the project."""
126*d9f75844SAndroid Build Coastguard Worker  src_dir = starting_dir
127*d9f75844SAndroid Build Coastguard Worker  while os.path.basename(src_dir) != 'src':
128*d9f75844SAndroid Build Coastguard Worker    src_dir = os.path.normpath(os.path.join(src_dir, os.pardir))
129*d9f75844SAndroid Build Coastguard Worker  return src_dir
130*d9f75844SAndroid Build Coastguard Worker
131*d9f75844SAndroid Build Coastguard Worker
132*d9f75844SAndroid Build Coastguard Worker@contextmanager
133*d9f75844SAndroid Build Coastguard Workerdef _AddToPath(*paths):
134*d9f75844SAndroid Build Coastguard Worker  original_sys_path = sys.path
135*d9f75844SAndroid Build Coastguard Worker  sys.path.extend(paths)
136*d9f75844SAndroid Build Coastguard Worker  try:
137*d9f75844SAndroid Build Coastguard Worker    yield
138*d9f75844SAndroid Build Coastguard Worker  finally:
139*d9f75844SAndroid Build Coastguard Worker    # Restore sys.path to what it was before.
140*d9f75844SAndroid Build Coastguard Worker    sys.path = original_sys_path
141*d9f75844SAndroid Build Coastguard Worker
142*d9f75844SAndroid Build Coastguard Worker
143*d9f75844SAndroid Build Coastguard Workerdef VerifyNativeApiHeadersListIsValid(input_api, output_api):
144*d9f75844SAndroid Build Coastguard Worker  """Ensures the list of native API header directories is up to date."""
145*d9f75844SAndroid Build Coastguard Worker  non_existing_paths = []
146*d9f75844SAndroid Build Coastguard Worker  native_api_full_paths = [
147*d9f75844SAndroid Build Coastguard Worker      input_api.os_path.join(input_api.PresubmitLocalPath(), *path.split('/'))
148*d9f75844SAndroid Build Coastguard Worker      for path in API_DIRS
149*d9f75844SAndroid Build Coastguard Worker  ]
150*d9f75844SAndroid Build Coastguard Worker  for path in native_api_full_paths:
151*d9f75844SAndroid Build Coastguard Worker    if not os.path.isdir(path):
152*d9f75844SAndroid Build Coastguard Worker      non_existing_paths.append(path)
153*d9f75844SAndroid Build Coastguard Worker  if non_existing_paths:
154*d9f75844SAndroid Build Coastguard Worker    return [
155*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
156*d9f75844SAndroid Build Coastguard Worker            'Directories to native API headers have changed which has made '
157*d9f75844SAndroid Build Coastguard Worker            'the list in PRESUBMIT.py outdated.\nPlease update it to the '
158*d9f75844SAndroid Build Coastguard Worker            'current location of our native APIs.', non_existing_paths)
159*d9f75844SAndroid Build Coastguard Worker    ]
160*d9f75844SAndroid Build Coastguard Worker  return []
161*d9f75844SAndroid Build Coastguard Worker
162*d9f75844SAndroid Build Coastguard Worker
163*d9f75844SAndroid Build Coastguard WorkerAPI_CHANGE_MSG = """
164*d9f75844SAndroid Build Coastguard WorkerYou seem to be changing native API header files. Please make sure that you:
165*d9f75844SAndroid Build Coastguard Worker  1. Make compatible changes that don't break existing clients. Usually
166*d9f75844SAndroid Build Coastguard Worker     this is done by keeping the existing method signatures unchanged.
167*d9f75844SAndroid Build Coastguard Worker  2. Mark the old stuff as deprecated (use the ABSL_DEPRECATED macro).
168*d9f75844SAndroid Build Coastguard Worker  3. Create a timeline and plan for when the deprecated stuff will be
169*d9f75844SAndroid Build Coastguard Worker     removed. (The amount of time we give users to change their code
170*d9f75844SAndroid Build Coastguard Worker     should be informed by how much work it is for them. If they just
171*d9f75844SAndroid Build Coastguard Worker     need to replace one name with another or something equally
172*d9f75844SAndroid Build Coastguard Worker     simple, 1-2 weeks might be good; if they need to do serious work,
173*d9f75844SAndroid Build Coastguard Worker     up to 3 months may be called for.)
174*d9f75844SAndroid Build Coastguard Worker  4. Update/inform existing downstream code owners to stop using the
175*d9f75844SAndroid Build Coastguard Worker     deprecated stuff. (Send announcements to
176*d9f75844SAndroid Build Coastguard Worker     [email protected] and [email protected].)
177*d9f75844SAndroid Build Coastguard Worker  5. Remove the deprecated stuff, once the agreed-upon amount of time
178*d9f75844SAndroid Build Coastguard Worker     has passed.
179*d9f75844SAndroid Build Coastguard WorkerRelated files:
180*d9f75844SAndroid Build Coastguard Worker"""
181*d9f75844SAndroid Build Coastguard Worker
182*d9f75844SAndroid Build Coastguard Worker
183*d9f75844SAndroid Build Coastguard Workerdef CheckNativeApiHeaderChanges(input_api, output_api):
184*d9f75844SAndroid Build Coastguard Worker  """Checks to remind proper changing of native APIs."""
185*d9f75844SAndroid Build Coastguard Worker  files = []
186*d9f75844SAndroid Build Coastguard Worker  source_file_filter = lambda x: input_api.FilterSourceFile(
187*d9f75844SAndroid Build Coastguard Worker      x, files_to_check=[r'.+\.(gn|gni|h)$'])
188*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(source_file_filter):
189*d9f75844SAndroid Build Coastguard Worker    for path in API_DIRS:
190*d9f75844SAndroid Build Coastguard Worker      dn = os.path.dirname(f.LocalPath())
191*d9f75844SAndroid Build Coastguard Worker      if path == 'api':
192*d9f75844SAndroid Build Coastguard Worker        # Special case: Subdirectories included.
193*d9f75844SAndroid Build Coastguard Worker        if dn == 'api' or dn.startswith('api/'):
194*d9f75844SAndroid Build Coastguard Worker          files.append(f.LocalPath())
195*d9f75844SAndroid Build Coastguard Worker      else:
196*d9f75844SAndroid Build Coastguard Worker        # Normal case: Subdirectories not included.
197*d9f75844SAndroid Build Coastguard Worker        if dn == path:
198*d9f75844SAndroid Build Coastguard Worker          files.append(f.LocalPath())
199*d9f75844SAndroid Build Coastguard Worker
200*d9f75844SAndroid Build Coastguard Worker  if files:
201*d9f75844SAndroid Build Coastguard Worker    return [output_api.PresubmitNotifyResult(API_CHANGE_MSG, files)]
202*d9f75844SAndroid Build Coastguard Worker  return []
203*d9f75844SAndroid Build Coastguard Worker
204*d9f75844SAndroid Build Coastguard Worker
205*d9f75844SAndroid Build Coastguard Workerdef CheckNoIOStreamInHeaders(input_api, output_api, source_file_filter):
206*d9f75844SAndroid Build Coastguard Worker  """Checks to make sure no .h files include <iostream>."""
207*d9f75844SAndroid Build Coastguard Worker  files = []
208*d9f75844SAndroid Build Coastguard Worker  pattern = input_api.re.compile(r'^#include\s*<iostream>',
209*d9f75844SAndroid Build Coastguard Worker                                 input_api.re.MULTILINE)
210*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter(
211*d9f75844SAndroid Build Coastguard Worker      x))
212*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
213*d9f75844SAndroid Build Coastguard Worker    if not f.LocalPath().endswith('.h'):
214*d9f75844SAndroid Build Coastguard Worker      continue
215*d9f75844SAndroid Build Coastguard Worker    contents = input_api.ReadFile(f)
216*d9f75844SAndroid Build Coastguard Worker    if pattern.search(contents):
217*d9f75844SAndroid Build Coastguard Worker      files.append(f)
218*d9f75844SAndroid Build Coastguard Worker
219*d9f75844SAndroid Build Coastguard Worker  if len(files) > 0:
220*d9f75844SAndroid Build Coastguard Worker    return [
221*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
222*d9f75844SAndroid Build Coastguard Worker            'Do not #include <iostream> in header files, since it inserts '
223*d9f75844SAndroid Build Coastguard Worker            'static initialization into every file including the header. '
224*d9f75844SAndroid Build Coastguard Worker            'Instead, #include <ostream>. See http://crbug.com/94794', files)
225*d9f75844SAndroid Build Coastguard Worker    ]
226*d9f75844SAndroid Build Coastguard Worker  return []
227*d9f75844SAndroid Build Coastguard Worker
228*d9f75844SAndroid Build Coastguard Worker
229*d9f75844SAndroid Build Coastguard Workerdef CheckNoPragmaOnce(input_api, output_api, source_file_filter):
230*d9f75844SAndroid Build Coastguard Worker  """Make sure that banned functions are not used."""
231*d9f75844SAndroid Build Coastguard Worker  files = []
232*d9f75844SAndroid Build Coastguard Worker  pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
233*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter(
234*d9f75844SAndroid Build Coastguard Worker      x))
235*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
236*d9f75844SAndroid Build Coastguard Worker    if not f.LocalPath().endswith('.h'):
237*d9f75844SAndroid Build Coastguard Worker      continue
238*d9f75844SAndroid Build Coastguard Worker    contents = input_api.ReadFile(f)
239*d9f75844SAndroid Build Coastguard Worker    if pattern.search(contents):
240*d9f75844SAndroid Build Coastguard Worker      files.append(f)
241*d9f75844SAndroid Build Coastguard Worker
242*d9f75844SAndroid Build Coastguard Worker  if files:
243*d9f75844SAndroid Build Coastguard Worker    return [
244*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
245*d9f75844SAndroid Build Coastguard Worker            'Do not use #pragma once in header files.\n'
246*d9f75844SAndroid Build Coastguard Worker            'See http://www.chromium.org/developers/coding-style'
247*d9f75844SAndroid Build Coastguard Worker            '#TOC-File-headers', files)
248*d9f75844SAndroid Build Coastguard Worker    ]
249*d9f75844SAndroid Build Coastguard Worker  return []
250*d9f75844SAndroid Build Coastguard Worker
251*d9f75844SAndroid Build Coastguard Worker
252*d9f75844SAndroid Build Coastguard Workerdef CheckNoFRIEND_TEST(# pylint: disable=invalid-name
253*d9f75844SAndroid Build Coastguard Worker        input_api,
254*d9f75844SAndroid Build Coastguard Worker        output_api,
255*d9f75844SAndroid Build Coastguard Worker        source_file_filter):
256*d9f75844SAndroid Build Coastguard Worker  """Make sure that gtest's FRIEND_TEST() macro is not used, the
257*d9f75844SAndroid Build Coastguard Worker  FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
258*d9f75844SAndroid Build Coastguard Worker  used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
259*d9f75844SAndroid Build Coastguard Worker  problems = []
260*d9f75844SAndroid Build Coastguard Worker
261*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) and
262*d9f75844SAndroid Build Coastguard Worker                           source_file_filter(f))
263*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles(file_filter=file_filter):
264*d9f75844SAndroid Build Coastguard Worker    for line_num, line in f.ChangedContents():
265*d9f75844SAndroid Build Coastguard Worker      if 'FRIEND_TEST(' in line:
266*d9f75844SAndroid Build Coastguard Worker        problems.append('    %s:%d' % (f.LocalPath(), line_num))
267*d9f75844SAndroid Build Coastguard Worker
268*d9f75844SAndroid Build Coastguard Worker  if not problems:
269*d9f75844SAndroid Build Coastguard Worker    return []
270*d9f75844SAndroid Build Coastguard Worker  return [
271*d9f75844SAndroid Build Coastguard Worker      output_api.PresubmitPromptWarning(
272*d9f75844SAndroid Build Coastguard Worker          'WebRTC\'s code should not use gtest\'s FRIEND_TEST() macro. '
273*d9f75844SAndroid Build Coastguard Worker          'Include testsupport/gtest_prod_util.h and use '
274*d9f75844SAndroid Build Coastguard Worker          'FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))
275*d9f75844SAndroid Build Coastguard Worker  ]
276*d9f75844SAndroid Build Coastguard Worker
277*d9f75844SAndroid Build Coastguard Worker
278*d9f75844SAndroid Build Coastguard Workerdef IsLintDisabled(disabled_paths, file_path):
279*d9f75844SAndroid Build Coastguard Worker  """ Checks if a file is disabled for lint check."""
280*d9f75844SAndroid Build Coastguard Worker  for path in disabled_paths:
281*d9f75844SAndroid Build Coastguard Worker    if file_path == path or os.path.dirname(file_path).startswith(path):
282*d9f75844SAndroid Build Coastguard Worker      return True
283*d9f75844SAndroid Build Coastguard Worker  return False
284*d9f75844SAndroid Build Coastguard Worker
285*d9f75844SAndroid Build Coastguard Worker
286*d9f75844SAndroid Build Coastguard Workerdef CheckApprovedFilesLintClean(input_api, output_api,
287*d9f75844SAndroid Build Coastguard Worker                                source_file_filter=None):
288*d9f75844SAndroid Build Coastguard Worker  """Checks that all new or non-exempt .cc and .h files pass cpplint.py.
289*d9f75844SAndroid Build Coastguard Worker  This check is based on CheckChangeLintsClean in
290*d9f75844SAndroid Build Coastguard Worker  depot_tools/presubmit_canned_checks.py but has less filters and only checks
291*d9f75844SAndroid Build Coastguard Worker  added files."""
292*d9f75844SAndroid Build Coastguard Worker  result = []
293*d9f75844SAndroid Build Coastguard Worker
294*d9f75844SAndroid Build Coastguard Worker  # Initialize cpplint.
295*d9f75844SAndroid Build Coastguard Worker  import cpplint
296*d9f75844SAndroid Build Coastguard Worker  # Access to a protected member _XX of a client class
297*d9f75844SAndroid Build Coastguard Worker  # pylint: disable=W0212
298*d9f75844SAndroid Build Coastguard Worker  cpplint._cpplint_state.ResetErrorCounts()
299*d9f75844SAndroid Build Coastguard Worker
300*d9f75844SAndroid Build Coastguard Worker  lint_filters = cpplint._Filters()
301*d9f75844SAndroid Build Coastguard Worker  lint_filters.extend(DISABLED_LINT_FILTERS)
302*d9f75844SAndroid Build Coastguard Worker  cpplint._SetFilters(','.join(lint_filters))
303*d9f75844SAndroid Build Coastguard Worker
304*d9f75844SAndroid Build Coastguard Worker  # Create a platform independent exempt list for cpplint.
305*d9f75844SAndroid Build Coastguard Worker  disabled_paths = [
306*d9f75844SAndroid Build Coastguard Worker      input_api.os_path.join(*path.split('/')) for path in CPPLINT_EXCEPTIONS
307*d9f75844SAndroid Build Coastguard Worker  ]
308*d9f75844SAndroid Build Coastguard Worker
309*d9f75844SAndroid Build Coastguard Worker  # Use the strictest verbosity level for cpplint.py (level 1) which is the
310*d9f75844SAndroid Build Coastguard Worker  # default when running cpplint.py from command line. To make it possible to
311*d9f75844SAndroid Build Coastguard Worker  # work with not-yet-converted code, we're only applying it to new (or
312*d9f75844SAndroid Build Coastguard Worker  # moved/renamed) files and files not listed in CPPLINT_EXCEPTIONS.
313*d9f75844SAndroid Build Coastguard Worker  verbosity_level = 1
314*d9f75844SAndroid Build Coastguard Worker  files = []
315*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(source_file_filter):
316*d9f75844SAndroid Build Coastguard Worker    # Note that moved/renamed files also count as added.
317*d9f75844SAndroid Build Coastguard Worker    if f.Action() == 'A' or not IsLintDisabled(disabled_paths, f.LocalPath()):
318*d9f75844SAndroid Build Coastguard Worker      files.append(f.AbsoluteLocalPath())
319*d9f75844SAndroid Build Coastguard Worker
320*d9f75844SAndroid Build Coastguard Worker  for file_name in files:
321*d9f75844SAndroid Build Coastguard Worker    cpplint.ProcessFile(file_name, verbosity_level)
322*d9f75844SAndroid Build Coastguard Worker
323*d9f75844SAndroid Build Coastguard Worker  if cpplint._cpplint_state.error_count > 0:
324*d9f75844SAndroid Build Coastguard Worker    if input_api.is_committing:
325*d9f75844SAndroid Build Coastguard Worker      res_type = output_api.PresubmitError
326*d9f75844SAndroid Build Coastguard Worker    else:
327*d9f75844SAndroid Build Coastguard Worker      res_type = output_api.PresubmitPromptWarning
328*d9f75844SAndroid Build Coastguard Worker    result = [res_type('Changelist failed cpplint.py check.')]
329*d9f75844SAndroid Build Coastguard Worker
330*d9f75844SAndroid Build Coastguard Worker  return result
331*d9f75844SAndroid Build Coastguard Worker
332*d9f75844SAndroid Build Coastguard Worker
333*d9f75844SAndroid Build Coastguard Workerdef CheckNoSourcesAbove(input_api, gn_files, output_api):
334*d9f75844SAndroid Build Coastguard Worker  # Disallow referencing source files with paths above the GN file location.
335*d9f75844SAndroid Build Coastguard Worker  source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]',
336*d9f75844SAndroid Build Coastguard Worker                                        re.MULTILINE | re.DOTALL)
337*d9f75844SAndroid Build Coastguard Worker  file_pattern = input_api.re.compile(r'"((\.\./.*?)|(//.*?))"')
338*d9f75844SAndroid Build Coastguard Worker  violating_gn_files = set()
339*d9f75844SAndroid Build Coastguard Worker  violating_source_entries = []
340*d9f75844SAndroid Build Coastguard Worker  for gn_file in gn_files:
341*d9f75844SAndroid Build Coastguard Worker    contents = input_api.ReadFile(gn_file)
342*d9f75844SAndroid Build Coastguard Worker    for source_block_match in source_pattern.finditer(contents):
343*d9f75844SAndroid Build Coastguard Worker      # Find all source list entries starting with ../ in the source block
344*d9f75844SAndroid Build Coastguard Worker      # (exclude overrides entries).
345*d9f75844SAndroid Build Coastguard Worker      for file_list_match in file_pattern.finditer(source_block_match.group(1)):
346*d9f75844SAndroid Build Coastguard Worker        source_file = file_list_match.group(1)
347*d9f75844SAndroid Build Coastguard Worker        if 'overrides/' not in source_file:
348*d9f75844SAndroid Build Coastguard Worker          violating_source_entries.append(source_file)
349*d9f75844SAndroid Build Coastguard Worker          violating_gn_files.add(gn_file)
350*d9f75844SAndroid Build Coastguard Worker  if violating_gn_files:
351*d9f75844SAndroid Build Coastguard Worker    return [
352*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
353*d9f75844SAndroid Build Coastguard Worker            'Referencing source files above the directory of the GN file '
354*d9f75844SAndroid Build Coastguard Worker            'is not allowed. Please introduce new GN targets in the proper '
355*d9f75844SAndroid Build Coastguard Worker            'location instead.\n'
356*d9f75844SAndroid Build Coastguard Worker            'Invalid source entries:\n'
357*d9f75844SAndroid Build Coastguard Worker            '%s\n'
358*d9f75844SAndroid Build Coastguard Worker            'Violating GN files:' % '\n'.join(violating_source_entries),
359*d9f75844SAndroid Build Coastguard Worker            items=violating_gn_files)
360*d9f75844SAndroid Build Coastguard Worker    ]
361*d9f75844SAndroid Build Coastguard Worker  return []
362*d9f75844SAndroid Build Coastguard Worker
363*d9f75844SAndroid Build Coastguard Worker
364*d9f75844SAndroid Build Coastguard Workerdef CheckAbseilDependencies(input_api, gn_files, output_api):
365*d9f75844SAndroid Build Coastguard Worker  """Checks that Abseil dependencies are declared in `absl_deps`."""
366*d9f75844SAndroid Build Coastguard Worker  absl_re = re.compile(r'third_party/abseil-cpp', re.MULTILINE | re.DOTALL)
367*d9f75844SAndroid Build Coastguard Worker  target_types_to_check = [
368*d9f75844SAndroid Build Coastguard Worker      'rtc_library',
369*d9f75844SAndroid Build Coastguard Worker      'rtc_source_set',
370*d9f75844SAndroid Build Coastguard Worker      'rtc_static_library',
371*d9f75844SAndroid Build Coastguard Worker      'webrtc_fuzzer_test',
372*d9f75844SAndroid Build Coastguard Worker  ]
373*d9f75844SAndroid Build Coastguard Worker  error_msg = ('Abseil dependencies in target "%s" (file: %s) '
374*d9f75844SAndroid Build Coastguard Worker               'should be moved to the "absl_deps" parameter.')
375*d9f75844SAndroid Build Coastguard Worker  errors = []
376*d9f75844SAndroid Build Coastguard Worker
377*d9f75844SAndroid Build Coastguard Worker  # pylint: disable=too-many-nested-blocks
378*d9f75844SAndroid Build Coastguard Worker  for gn_file in gn_files:
379*d9f75844SAndroid Build Coastguard Worker    gn_file_content = input_api.ReadFile(gn_file)
380*d9f75844SAndroid Build Coastguard Worker    for target_match in TARGET_RE.finditer(gn_file_content):
381*d9f75844SAndroid Build Coastguard Worker      target_type = target_match.group('target_type')
382*d9f75844SAndroid Build Coastguard Worker      target_name = target_match.group('target_name')
383*d9f75844SAndroid Build Coastguard Worker      target_contents = target_match.group('target_contents')
384*d9f75844SAndroid Build Coastguard Worker      if target_type in target_types_to_check:
385*d9f75844SAndroid Build Coastguard Worker        for deps_match in DEPS_RE.finditer(target_contents):
386*d9f75844SAndroid Build Coastguard Worker          deps = deps_match.group('deps').splitlines()
387*d9f75844SAndroid Build Coastguard Worker          for dep in deps:
388*d9f75844SAndroid Build Coastguard Worker            if re.search(absl_re, dep):
389*d9f75844SAndroid Build Coastguard Worker              errors.append(
390*d9f75844SAndroid Build Coastguard Worker                  output_api.PresubmitError(error_msg %
391*d9f75844SAndroid Build Coastguard Worker                                            (target_name, gn_file.LocalPath())))
392*d9f75844SAndroid Build Coastguard Worker              break  # no need to warn more than once per target
393*d9f75844SAndroid Build Coastguard Worker  return errors
394*d9f75844SAndroid Build Coastguard Worker
395*d9f75844SAndroid Build Coastguard Worker
396*d9f75844SAndroid Build Coastguard Workerdef CheckNoMixingSources(input_api, gn_files, output_api):
397*d9f75844SAndroid Build Coastguard Worker  """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target.
398*d9f75844SAndroid Build Coastguard Worker
399*d9f75844SAndroid Build Coastguard Worker  See bugs.webrtc.org/7743 for more context.
400*d9f75844SAndroid Build Coastguard Worker  """
401*d9f75844SAndroid Build Coastguard Worker
402*d9f75844SAndroid Build Coastguard Worker  def _MoreThanOneSourceUsed(*sources_lists):
403*d9f75844SAndroid Build Coastguard Worker    sources_used = 0
404*d9f75844SAndroid Build Coastguard Worker    for source_list in sources_lists:
405*d9f75844SAndroid Build Coastguard Worker      if len(source_list) > 0:
406*d9f75844SAndroid Build Coastguard Worker        sources_used += 1
407*d9f75844SAndroid Build Coastguard Worker    return sources_used > 1
408*d9f75844SAndroid Build Coastguard Worker
409*d9f75844SAndroid Build Coastguard Worker  errors = defaultdict(lambda: [])
410*d9f75844SAndroid Build Coastguard Worker  for gn_file in gn_files:
411*d9f75844SAndroid Build Coastguard Worker    gn_file_content = input_api.ReadFile(gn_file)
412*d9f75844SAndroid Build Coastguard Worker    for target_match in TARGET_RE.finditer(gn_file_content):
413*d9f75844SAndroid Build Coastguard Worker      # list_of_sources is a list of tuples of the form
414*d9f75844SAndroid Build Coastguard Worker      # (c_files, cc_files, objc_files) that keeps track of all the
415*d9f75844SAndroid Build Coastguard Worker      # sources defined in a target. A GN target can have more that
416*d9f75844SAndroid Build Coastguard Worker      # on definition of sources (since it supports if/else statements).
417*d9f75844SAndroid Build Coastguard Worker      # E.g.:
418*d9f75844SAndroid Build Coastguard Worker      # rtc_static_library("foo") {
419*d9f75844SAndroid Build Coastguard Worker      #   if (is_win) {
420*d9f75844SAndroid Build Coastguard Worker      #     sources = [ "foo.cc" ]
421*d9f75844SAndroid Build Coastguard Worker      #   } else {
422*d9f75844SAndroid Build Coastguard Worker      #     sources = [ "foo.mm" ]
423*d9f75844SAndroid Build Coastguard Worker      #   }
424*d9f75844SAndroid Build Coastguard Worker      # }
425*d9f75844SAndroid Build Coastguard Worker      # This is allowed and the presubmit check should support this case.
426*d9f75844SAndroid Build Coastguard Worker      list_of_sources = []
427*d9f75844SAndroid Build Coastguard Worker      c_files = []
428*d9f75844SAndroid Build Coastguard Worker      cc_files = []
429*d9f75844SAndroid Build Coastguard Worker      objc_files = []
430*d9f75844SAndroid Build Coastguard Worker      target_name = target_match.group('target_name')
431*d9f75844SAndroid Build Coastguard Worker      target_contents = target_match.group('target_contents')
432*d9f75844SAndroid Build Coastguard Worker      for sources_match in SOURCES_RE.finditer(target_contents):
433*d9f75844SAndroid Build Coastguard Worker        if '+=' not in sources_match.group(0):
434*d9f75844SAndroid Build Coastguard Worker          if c_files or cc_files or objc_files:
435*d9f75844SAndroid Build Coastguard Worker            list_of_sources.append((c_files, cc_files, objc_files))
436*d9f75844SAndroid Build Coastguard Worker          c_files = []
437*d9f75844SAndroid Build Coastguard Worker          cc_files = []
438*d9f75844SAndroid Build Coastguard Worker          objc_files = []
439*d9f75844SAndroid Build Coastguard Worker        for file_match in FILE_PATH_RE.finditer(sources_match.group(1)):
440*d9f75844SAndroid Build Coastguard Worker          file_path = file_match.group('file_path')
441*d9f75844SAndroid Build Coastguard Worker          extension = file_match.group('extension')
442*d9f75844SAndroid Build Coastguard Worker          if extension == '.c':
443*d9f75844SAndroid Build Coastguard Worker            c_files.append(file_path + extension)
444*d9f75844SAndroid Build Coastguard Worker          if extension == '.cc':
445*d9f75844SAndroid Build Coastguard Worker            cc_files.append(file_path + extension)
446*d9f75844SAndroid Build Coastguard Worker          if extension in ['.m', '.mm']:
447*d9f75844SAndroid Build Coastguard Worker            objc_files.append(file_path + extension)
448*d9f75844SAndroid Build Coastguard Worker      list_of_sources.append((c_files, cc_files, objc_files))
449*d9f75844SAndroid Build Coastguard Worker      for c_files_list, cc_files_list, objc_files_list in list_of_sources:
450*d9f75844SAndroid Build Coastguard Worker        if _MoreThanOneSourceUsed(c_files_list, cc_files_list, objc_files_list):
451*d9f75844SAndroid Build Coastguard Worker          all_sources = sorted(c_files_list + cc_files_list + objc_files_list)
452*d9f75844SAndroid Build Coastguard Worker          errors[gn_file.LocalPath()].append((target_name, all_sources))
453*d9f75844SAndroid Build Coastguard Worker  if errors:
454*d9f75844SAndroid Build Coastguard Worker    return [
455*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
456*d9f75844SAndroid Build Coastguard Worker            'GN targets cannot mix .c, .cc and .m (or .mm) source files.\n'
457*d9f75844SAndroid Build Coastguard Worker            'Please create a separate target for each collection of '
458*d9f75844SAndroid Build Coastguard Worker            'sources.\n'
459*d9f75844SAndroid Build Coastguard Worker            'Mixed sources: \n'
460*d9f75844SAndroid Build Coastguard Worker            '%s\n'
461*d9f75844SAndroid Build Coastguard Worker            'Violating GN files:\n%s\n' %
462*d9f75844SAndroid Build Coastguard Worker            (json.dumps(errors, indent=2), '\n'.join(list(errors.keys()))))
463*d9f75844SAndroid Build Coastguard Worker    ]
464*d9f75844SAndroid Build Coastguard Worker  return []
465*d9f75844SAndroid Build Coastguard Worker
466*d9f75844SAndroid Build Coastguard Worker
467*d9f75844SAndroid Build Coastguard Workerdef CheckNoPackageBoundaryViolations(input_api, gn_files, output_api):
468*d9f75844SAndroid Build Coastguard Worker  cwd = input_api.PresubmitLocalPath()
469*d9f75844SAndroid Build Coastguard Worker  with _AddToPath(
470*d9f75844SAndroid Build Coastguard Worker      input_api.os_path.join(cwd, 'tools_webrtc', 'presubmit_checks_lib')):
471*d9f75844SAndroid Build Coastguard Worker    from check_package_boundaries import CheckPackageBoundaries
472*d9f75844SAndroid Build Coastguard Worker  build_files = [os.path.join(cwd, gn_file.LocalPath()) for gn_file in gn_files]
473*d9f75844SAndroid Build Coastguard Worker  errors = CheckPackageBoundaries(cwd, build_files)[:5]
474*d9f75844SAndroid Build Coastguard Worker  if errors:
475*d9f75844SAndroid Build Coastguard Worker    return [
476*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
477*d9f75844SAndroid Build Coastguard Worker            'There are package boundary violations in the following GN '
478*d9f75844SAndroid Build Coastguard Worker            'files:',
479*d9f75844SAndroid Build Coastguard Worker            long_text='\n\n'.join(str(err) for err in errors))
480*d9f75844SAndroid Build Coastguard Worker    ]
481*d9f75844SAndroid Build Coastguard Worker  return []
482*d9f75844SAndroid Build Coastguard Worker
483*d9f75844SAndroid Build Coastguard Worker
484*d9f75844SAndroid Build Coastguard Workerdef _ReportFileAndLine(filename, line_num):
485*d9f75844SAndroid Build Coastguard Worker  """Default error formatter for _FindNewViolationsOfRule."""
486*d9f75844SAndroid Build Coastguard Worker  return '%s (line %s)' % (filename, line_num)
487*d9f75844SAndroid Build Coastguard Worker
488*d9f75844SAndroid Build Coastguard Worker
489*d9f75844SAndroid Build Coastguard Workerdef CheckNoWarningSuppressionFlagsAreAdded(gn_files,
490*d9f75844SAndroid Build Coastguard Worker                                           input_api,
491*d9f75844SAndroid Build Coastguard Worker                                           output_api,
492*d9f75844SAndroid Build Coastguard Worker                                           error_formatter=_ReportFileAndLine):
493*d9f75844SAndroid Build Coastguard Worker  """Ensure warning suppression flags are not added without a reason."""
494*d9f75844SAndroid Build Coastguard Worker  msg = ('Usage of //build/config/clang:extra_warnings is discouraged '
495*d9f75844SAndroid Build Coastguard Worker         'in WebRTC.\n'
496*d9f75844SAndroid Build Coastguard Worker         'If you are not adding this code (e.g. you are just moving '
497*d9f75844SAndroid Build Coastguard Worker         'existing code) or you want to add an exception,\n'
498*d9f75844SAndroid Build Coastguard Worker         'you can add a comment on the line that causes the problem:\n\n'
499*d9f75844SAndroid Build Coastguard Worker         '"-Wno-odr"  # no-presubmit-check TODO(bugs.webrtc.org/BUG_ID)\n'
500*d9f75844SAndroid Build Coastguard Worker         '\n'
501*d9f75844SAndroid Build Coastguard Worker         'Affected files:\n')
502*d9f75844SAndroid Build Coastguard Worker  errors = []  # 2-element tuples with (file, line number)
503*d9f75844SAndroid Build Coastguard Worker  clang_warn_re = input_api.re.compile(r'//build/config/clang:extra_warnings')
504*d9f75844SAndroid Build Coastguard Worker  # pylint: disable-next=fixme
505*d9f75844SAndroid Build Coastguard Worker  no_presubmit_re = input_api.re.compile(
506*d9f75844SAndroid Build Coastguard Worker      r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)')
507*d9f75844SAndroid Build Coastguard Worker  for f in gn_files:
508*d9f75844SAndroid Build Coastguard Worker    for line_num, line in f.ChangedContents():
509*d9f75844SAndroid Build Coastguard Worker      if clang_warn_re.search(line) and not no_presubmit_re.search(line):
510*d9f75844SAndroid Build Coastguard Worker        errors.append(error_formatter(f.LocalPath(), line_num))
511*d9f75844SAndroid Build Coastguard Worker  if errors:
512*d9f75844SAndroid Build Coastguard Worker    return [output_api.PresubmitError(msg, errors)]
513*d9f75844SAndroid Build Coastguard Worker  return []
514*d9f75844SAndroid Build Coastguard Worker
515*d9f75844SAndroid Build Coastguard Worker
516*d9f75844SAndroid Build Coastguard Workerdef CheckNoTestCaseUsageIsAdded(input_api,
517*d9f75844SAndroid Build Coastguard Worker                                output_api,
518*d9f75844SAndroid Build Coastguard Worker                                source_file_filter,
519*d9f75844SAndroid Build Coastguard Worker                                error_formatter=_ReportFileAndLine):
520*d9f75844SAndroid Build Coastguard Worker  error_msg = ('Usage of legacy GoogleTest API detected!\nPlease use the '
521*d9f75844SAndroid Build Coastguard Worker               'new API: https://github.com/google/googletest/blob/master/'
522*d9f75844SAndroid Build Coastguard Worker               'googletest/docs/primer.md#beware-of-the-nomenclature.\n'
523*d9f75844SAndroid Build Coastguard Worker               'Affected files:\n')
524*d9f75844SAndroid Build Coastguard Worker  errors = []  # 2-element tuples with (file, line number)
525*d9f75844SAndroid Build Coastguard Worker  test_case_re = input_api.re.compile(r'TEST_CASE')
526*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: (source_file_filter(f) and f.LocalPath().endswith(
527*d9f75844SAndroid Build Coastguard Worker      '.cc'))
528*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
529*d9f75844SAndroid Build Coastguard Worker    for line_num, line in f.ChangedContents():
530*d9f75844SAndroid Build Coastguard Worker      if test_case_re.search(line):
531*d9f75844SAndroid Build Coastguard Worker        errors.append(error_formatter(f.LocalPath(), line_num))
532*d9f75844SAndroid Build Coastguard Worker  if errors:
533*d9f75844SAndroid Build Coastguard Worker    return [output_api.PresubmitError(error_msg, errors)]
534*d9f75844SAndroid Build Coastguard Worker  return []
535*d9f75844SAndroid Build Coastguard Worker
536*d9f75844SAndroid Build Coastguard Worker
537*d9f75844SAndroid Build Coastguard Workerdef CheckNoStreamUsageIsAdded(input_api,
538*d9f75844SAndroid Build Coastguard Worker                              output_api,
539*d9f75844SAndroid Build Coastguard Worker                              source_file_filter,
540*d9f75844SAndroid Build Coastguard Worker                              error_formatter=_ReportFileAndLine):
541*d9f75844SAndroid Build Coastguard Worker  """Make sure that no more dependencies on stringstream are added."""
542*d9f75844SAndroid Build Coastguard Worker  error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
543*d9f75844SAndroid Build Coastguard Worker               'deprecated.\n'
544*d9f75844SAndroid Build Coastguard Worker               'This includes the following types:\n'
545*d9f75844SAndroid Build Coastguard Worker               'std::istringstream, std::ostringstream, std::wistringstream, '
546*d9f75844SAndroid Build Coastguard Worker               'std::wostringstream,\n'
547*d9f75844SAndroid Build Coastguard Worker               'std::wstringstream, std::ostream, std::wostream, std::istream,'
548*d9f75844SAndroid Build Coastguard Worker               'std::wistream,\n'
549*d9f75844SAndroid Build Coastguard Worker               'std::iostream, std::wiostream.\n'
550*d9f75844SAndroid Build Coastguard Worker               'If you are not adding this code (e.g. you are just moving '
551*d9f75844SAndroid Build Coastguard Worker               'existing code),\n'
552*d9f75844SAndroid Build Coastguard Worker               'you can add a comment on the line that causes the problem:\n\n'
553*d9f75844SAndroid Build Coastguard Worker               '#include <sstream>  // no-presubmit-check TODO(webrtc:8982)\n'
554*d9f75844SAndroid Build Coastguard Worker               'std::ostream& F() {  // no-presubmit-check TODO(webrtc:8982)\n'
555*d9f75844SAndroid Build Coastguard Worker               '\n'
556*d9f75844SAndroid Build Coastguard Worker               'If you are adding new code, consider using '
557*d9f75844SAndroid Build Coastguard Worker               'rtc::SimpleStringBuilder\n'
558*d9f75844SAndroid Build Coastguard Worker               '(in rtc_base/strings/string_builder.h).\n'
559*d9f75844SAndroid Build Coastguard Worker               'Affected files:\n')
560*d9f75844SAndroid Build Coastguard Worker  errors = []  # 2-element tuples with (file, line number)
561*d9f75844SAndroid Build Coastguard Worker  include_re = input_api.re.compile(r'#include <(i|o|s)stream>')
562*d9f75844SAndroid Build Coastguard Worker  usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream')
563*d9f75844SAndroid Build Coastguard Worker  no_presubmit_re = input_api.re.compile(
564*d9f75844SAndroid Build Coastguard Worker      r'// no-presubmit-check TODO\(webrtc:8982\)')
565*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter(
566*d9f75844SAndroid Build Coastguard Worker      x))
567*d9f75844SAndroid Build Coastguard Worker
568*d9f75844SAndroid Build Coastguard Worker  def _IsException(file_path):
569*d9f75844SAndroid Build Coastguard Worker    is_test = any(
570*d9f75844SAndroid Build Coastguard Worker        file_path.endswith(x)
571*d9f75844SAndroid Build Coastguard Worker        for x in ['_test.cc', '_tests.cc', '_unittest.cc', '_unittests.cc'])
572*d9f75844SAndroid Build Coastguard Worker    return (file_path.startswith('examples') or file_path.startswith('test')
573*d9f75844SAndroid Build Coastguard Worker            or is_test)
574*d9f75844SAndroid Build Coastguard Worker
575*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
576*d9f75844SAndroid Build Coastguard Worker    # Usage of stringstream is allowed under examples/ and in tests.
577*d9f75844SAndroid Build Coastguard Worker    if f.LocalPath() == 'PRESUBMIT.py' or _IsException(f.LocalPath()):
578*d9f75844SAndroid Build Coastguard Worker      continue
579*d9f75844SAndroid Build Coastguard Worker    for line_num, line in f.ChangedContents():
580*d9f75844SAndroid Build Coastguard Worker      if ((include_re.search(line) or usage_re.search(line))
581*d9f75844SAndroid Build Coastguard Worker          and not no_presubmit_re.search(line)):
582*d9f75844SAndroid Build Coastguard Worker        errors.append(error_formatter(f.LocalPath(), line_num))
583*d9f75844SAndroid Build Coastguard Worker  if errors:
584*d9f75844SAndroid Build Coastguard Worker    return [output_api.PresubmitError(error_msg, errors)]
585*d9f75844SAndroid Build Coastguard Worker  return []
586*d9f75844SAndroid Build Coastguard Worker
587*d9f75844SAndroid Build Coastguard Worker
588*d9f75844SAndroid Build Coastguard Workerdef CheckPublicDepsIsNotUsed(gn_files, input_api, output_api):
589*d9f75844SAndroid Build Coastguard Worker  """Checks that public_deps is not used without a good reason."""
590*d9f75844SAndroid Build Coastguard Worker  result = []
591*d9f75844SAndroid Build Coastguard Worker  no_presubmit_check_re = input_api.re.compile(
592*d9f75844SAndroid Build Coastguard Worker      r'# no-presubmit-check TODO\(webrtc:\d+\)')
593*d9f75844SAndroid Build Coastguard Worker  error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files '
594*d9f75844SAndroid Build Coastguard Worker               'because it doesn\'t map well to downstream build systems.\n'
595*d9f75844SAndroid Build Coastguard Worker               'Used in: %s (line %d).\n'
596*d9f75844SAndroid Build Coastguard Worker               'If you are not adding this code (e.g. you are just moving '
597*d9f75844SAndroid Build Coastguard Worker               'existing code) or you have a good reason, you can add this '
598*d9f75844SAndroid Build Coastguard Worker               'comment (verbatim) on the line that causes the problem:\n\n'
599*d9f75844SAndroid Build Coastguard Worker               'public_deps = [  # no-presubmit-check TODO(webrtc:8603)\n')
600*d9f75844SAndroid Build Coastguard Worker  for affected_file in gn_files:
601*d9f75844SAndroid Build Coastguard Worker    for (line_number, affected_line) in affected_file.ChangedContents():
602*d9f75844SAndroid Build Coastguard Worker      if 'public_deps' in affected_line:
603*d9f75844SAndroid Build Coastguard Worker        surpressed = no_presubmit_check_re.search(affected_line)
604*d9f75844SAndroid Build Coastguard Worker        if not surpressed:
605*d9f75844SAndroid Build Coastguard Worker          result.append(
606*d9f75844SAndroid Build Coastguard Worker              output_api.PresubmitError(
607*d9f75844SAndroid Build Coastguard Worker                  error_msg % (affected_file.LocalPath(), line_number)))
608*d9f75844SAndroid Build Coastguard Worker  return result
609*d9f75844SAndroid Build Coastguard Worker
610*d9f75844SAndroid Build Coastguard Worker
611*d9f75844SAndroid Build Coastguard Workerdef CheckCheckIncludesIsNotUsed(gn_files, input_api, output_api):
612*d9f75844SAndroid Build Coastguard Worker  result = []
613*d9f75844SAndroid Build Coastguard Worker  error_msg = ('check_includes overrides are not allowed since it can cause '
614*d9f75844SAndroid Build Coastguard Worker               'incorrect dependencies to form. It effectively means that your '
615*d9f75844SAndroid Build Coastguard Worker               'module can include any .h file without depending on its '
616*d9f75844SAndroid Build Coastguard Worker               'corresponding target. There are some exceptional cases when '
617*d9f75844SAndroid Build Coastguard Worker               'this is allowed: if so, get approval from a .gn owner in the '
618*d9f75844SAndroid Build Coastguard Worker               'root OWNERS file.\n'
619*d9f75844SAndroid Build Coastguard Worker               'Used in: %s (line %d).')
620*d9f75844SAndroid Build Coastguard Worker  # pylint: disable-next=fixme
621*d9f75844SAndroid Build Coastguard Worker  no_presubmit_re = input_api.re.compile(
622*d9f75844SAndroid Build Coastguard Worker      r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)')
623*d9f75844SAndroid Build Coastguard Worker  for affected_file in gn_files:
624*d9f75844SAndroid Build Coastguard Worker    for (line_number, affected_line) in affected_file.ChangedContents():
625*d9f75844SAndroid Build Coastguard Worker      if ('check_includes' in affected_line
626*d9f75844SAndroid Build Coastguard Worker          and not no_presubmit_re.search(affected_line)):
627*d9f75844SAndroid Build Coastguard Worker        result.append(
628*d9f75844SAndroid Build Coastguard Worker            output_api.PresubmitError(error_msg %
629*d9f75844SAndroid Build Coastguard Worker                                      (affected_file.LocalPath(), line_number)))
630*d9f75844SAndroid Build Coastguard Worker  return result
631*d9f75844SAndroid Build Coastguard Worker
632*d9f75844SAndroid Build Coastguard Worker
633*d9f75844SAndroid Build Coastguard Workerdef CheckGnChanges(input_api, output_api):
634*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: (input_api.FilterSourceFile(
635*d9f75844SAndroid Build Coastguard Worker      x,
636*d9f75844SAndroid Build Coastguard Worker      files_to_check=(r'.+\.(gn|gni)$', ),
637*d9f75844SAndroid Build Coastguard Worker      files_to_skip=(r'.*/presubmit_checks_lib/testdata/.*', )))
638*d9f75844SAndroid Build Coastguard Worker
639*d9f75844SAndroid Build Coastguard Worker  gn_files = []
640*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
641*d9f75844SAndroid Build Coastguard Worker    gn_files.append(f)
642*d9f75844SAndroid Build Coastguard Worker
643*d9f75844SAndroid Build Coastguard Worker  result = []
644*d9f75844SAndroid Build Coastguard Worker  if gn_files:
645*d9f75844SAndroid Build Coastguard Worker    result.extend(CheckNoSourcesAbove(input_api, gn_files, output_api))
646*d9f75844SAndroid Build Coastguard Worker    result.extend(CheckNoMixingSources(input_api, gn_files, output_api))
647*d9f75844SAndroid Build Coastguard Worker    result.extend(CheckAbseilDependencies(input_api, gn_files, output_api))
648*d9f75844SAndroid Build Coastguard Worker    result.extend(
649*d9f75844SAndroid Build Coastguard Worker        CheckNoPackageBoundaryViolations(input_api, gn_files, output_api))
650*d9f75844SAndroid Build Coastguard Worker    result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, output_api))
651*d9f75844SAndroid Build Coastguard Worker    result.extend(CheckCheckIncludesIsNotUsed(gn_files, input_api, output_api))
652*d9f75844SAndroid Build Coastguard Worker    result.extend(
653*d9f75844SAndroid Build Coastguard Worker        CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, output_api))
654*d9f75844SAndroid Build Coastguard Worker  return result
655*d9f75844SAndroid Build Coastguard Worker
656*d9f75844SAndroid Build Coastguard Worker
657*d9f75844SAndroid Build Coastguard Workerdef CheckGnGen(input_api, output_api):
658*d9f75844SAndroid Build Coastguard Worker  """Runs `gn gen --check` with default args to detect mismatches between
659*d9f75844SAndroid Build Coastguard Worker  #includes and dependencies in the BUILD.gn files, as well as general build
660*d9f75844SAndroid Build Coastguard Worker  errors.
661*d9f75844SAndroid Build Coastguard Worker  """
662*d9f75844SAndroid Build Coastguard Worker  with _AddToPath(
663*d9f75844SAndroid Build Coastguard Worker      input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools_webrtc',
664*d9f75844SAndroid Build Coastguard Worker                             'presubmit_checks_lib')):
665*d9f75844SAndroid Build Coastguard Worker    from build_helpers import RunGnCheck
666*d9f75844SAndroid Build Coastguard Worker  errors = RunGnCheck(FindSrcDirPath(input_api.PresubmitLocalPath()))[:5]
667*d9f75844SAndroid Build Coastguard Worker  if errors:
668*d9f75844SAndroid Build Coastguard Worker    return [
669*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitPromptWarning(
670*d9f75844SAndroid Build Coastguard Worker            'Some #includes do not match the build dependency graph. '
671*d9f75844SAndroid Build Coastguard Worker            'Please run:\n'
672*d9f75844SAndroid Build Coastguard Worker            '  gn gen --check <out_dir>',
673*d9f75844SAndroid Build Coastguard Worker            long_text='\n\n'.join(errors))
674*d9f75844SAndroid Build Coastguard Worker    ]
675*d9f75844SAndroid Build Coastguard Worker  return []
676*d9f75844SAndroid Build Coastguard Worker
677*d9f75844SAndroid Build Coastguard Worker
678*d9f75844SAndroid Build Coastguard Workerdef CheckUnwantedDependencies(input_api, output_api, source_file_filter):
679*d9f75844SAndroid Build Coastguard Worker  """Runs checkdeps on #include statements added in this
680*d9f75844SAndroid Build Coastguard Worker  change. Breaking - rules is an error, breaking ! rules is a
681*d9f75844SAndroid Build Coastguard Worker  warning.
682*d9f75844SAndroid Build Coastguard Worker  """
683*d9f75844SAndroid Build Coastguard Worker  # Copied from Chromium's src/PRESUBMIT.py.
684*d9f75844SAndroid Build Coastguard Worker
685*d9f75844SAndroid Build Coastguard Worker  # We need to wait until we have an input_api object and use this
686*d9f75844SAndroid Build Coastguard Worker  # roundabout construct to import checkdeps because this file is
687*d9f75844SAndroid Build Coastguard Worker  # eval-ed and thus doesn't have __file__.
688*d9f75844SAndroid Build Coastguard Worker  src_path = FindSrcDirPath(input_api.PresubmitLocalPath())
689*d9f75844SAndroid Build Coastguard Worker  checkdeps_path = input_api.os_path.join(src_path, 'buildtools', 'checkdeps')
690*d9f75844SAndroid Build Coastguard Worker  if not os.path.exists(checkdeps_path):
691*d9f75844SAndroid Build Coastguard Worker    return [
692*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
693*d9f75844SAndroid Build Coastguard Worker            'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
694*d9f75844SAndroid Build Coastguard Worker            'download all the DEPS entries?' % checkdeps_path)
695*d9f75844SAndroid Build Coastguard Worker    ]
696*d9f75844SAndroid Build Coastguard Worker  with _AddToPath(checkdeps_path):
697*d9f75844SAndroid Build Coastguard Worker    import checkdeps
698*d9f75844SAndroid Build Coastguard Worker    from cpp_checker import CppChecker
699*d9f75844SAndroid Build Coastguard Worker    from rules import Rule
700*d9f75844SAndroid Build Coastguard Worker
701*d9f75844SAndroid Build Coastguard Worker  added_includes = []
702*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles(file_filter=source_file_filter):
703*d9f75844SAndroid Build Coastguard Worker    if not CppChecker.IsCppFile(f.LocalPath()):
704*d9f75844SAndroid Build Coastguard Worker      continue
705*d9f75844SAndroid Build Coastguard Worker
706*d9f75844SAndroid Build Coastguard Worker    changed_lines = [line for _, line in f.ChangedContents()]
707*d9f75844SAndroid Build Coastguard Worker    added_includes.append([f.LocalPath(), changed_lines])
708*d9f75844SAndroid Build Coastguard Worker
709*d9f75844SAndroid Build Coastguard Worker  deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
710*d9f75844SAndroid Build Coastguard Worker
711*d9f75844SAndroid Build Coastguard Worker  error_descriptions = []
712*d9f75844SAndroid Build Coastguard Worker  warning_descriptions = []
713*d9f75844SAndroid Build Coastguard Worker  for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
714*d9f75844SAndroid Build Coastguard Worker      added_includes):
715*d9f75844SAndroid Build Coastguard Worker    description_with_path = '%s\n    %s' % (path, rule_description)
716*d9f75844SAndroid Build Coastguard Worker    if rule_type == Rule.DISALLOW:
717*d9f75844SAndroid Build Coastguard Worker      error_descriptions.append(description_with_path)
718*d9f75844SAndroid Build Coastguard Worker    else:
719*d9f75844SAndroid Build Coastguard Worker      warning_descriptions.append(description_with_path)
720*d9f75844SAndroid Build Coastguard Worker
721*d9f75844SAndroid Build Coastguard Worker  results = []
722*d9f75844SAndroid Build Coastguard Worker  if error_descriptions:
723*d9f75844SAndroid Build Coastguard Worker    results.append(
724*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
725*d9f75844SAndroid Build Coastguard Worker            'You added one or more #includes that violate checkdeps rules.'
726*d9f75844SAndroid Build Coastguard Worker            '\nCheck that the DEPS files in these locations contain valid '
727*d9f75844SAndroid Build Coastguard Worker            'rules.\nSee '
728*d9f75844SAndroid Build Coastguard Worker            'https://cs.chromium.org/chromium/src/buildtools/checkdeps/ '
729*d9f75844SAndroid Build Coastguard Worker            'for more details about checkdeps.', error_descriptions))
730*d9f75844SAndroid Build Coastguard Worker  if warning_descriptions:
731*d9f75844SAndroid Build Coastguard Worker    results.append(
732*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitPromptOrNotify(
733*d9f75844SAndroid Build Coastguard Worker            'You added one or more #includes of files that are temporarily'
734*d9f75844SAndroid Build Coastguard Worker            '\nallowed but being removed. Can you avoid introducing the\n'
735*d9f75844SAndroid Build Coastguard Worker            '#include? See relevant DEPS file(s) for details and contacts.'
736*d9f75844SAndroid Build Coastguard Worker            '\nSee '
737*d9f75844SAndroid Build Coastguard Worker            'https://cs.chromium.org/chromium/src/buildtools/checkdeps/ '
738*d9f75844SAndroid Build Coastguard Worker            'for more details about checkdeps.', warning_descriptions))
739*d9f75844SAndroid Build Coastguard Worker  return results
740*d9f75844SAndroid Build Coastguard Worker
741*d9f75844SAndroid Build Coastguard Worker
742*d9f75844SAndroid Build Coastguard Workerdef CheckCommitMessageBugEntry(input_api, output_api):
743*d9f75844SAndroid Build Coastguard Worker  """Check that bug entries are well-formed in commit message."""
744*d9f75844SAndroid Build Coastguard Worker  bogus_bug_msg = (
745*d9f75844SAndroid Build Coastguard Worker      'Bogus Bug entry: %s. Please specify the issue tracker prefix and the '
746*d9f75844SAndroid Build Coastguard Worker      'issue number, separated by a colon, e.g. webrtc:123 or chromium:12345.')
747*d9f75844SAndroid Build Coastguard Worker  results = []
748*d9f75844SAndroid Build Coastguard Worker  for bug in input_api.change.BugsFromDescription():
749*d9f75844SAndroid Build Coastguard Worker    bug = bug.strip()
750*d9f75844SAndroid Build Coastguard Worker    if bug.lower() == 'none':
751*d9f75844SAndroid Build Coastguard Worker      continue
752*d9f75844SAndroid Build Coastguard Worker    if 'b/' not in bug and ':' not in bug:
753*d9f75844SAndroid Build Coastguard Worker      try:
754*d9f75844SAndroid Build Coastguard Worker        if int(bug) > 100000:
755*d9f75844SAndroid Build Coastguard Worker          # Rough indicator for current chromium bugs.
756*d9f75844SAndroid Build Coastguard Worker          prefix_guess = 'chromium'
757*d9f75844SAndroid Build Coastguard Worker        else:
758*d9f75844SAndroid Build Coastguard Worker          prefix_guess = 'webrtc'
759*d9f75844SAndroid Build Coastguard Worker        results.append('Bug entry requires issue tracker prefix, e.g. %s:%s' %
760*d9f75844SAndroid Build Coastguard Worker                       (prefix_guess, bug))
761*d9f75844SAndroid Build Coastguard Worker      except ValueError:
762*d9f75844SAndroid Build Coastguard Worker        results.append(bogus_bug_msg % bug)
763*d9f75844SAndroid Build Coastguard Worker    elif not (re.match(r'\w+:\d+', bug) or re.match(r'b/\d+', bug)):
764*d9f75844SAndroid Build Coastguard Worker      results.append(bogus_bug_msg % bug)
765*d9f75844SAndroid Build Coastguard Worker  return [output_api.PresubmitError(r) for r in results]
766*d9f75844SAndroid Build Coastguard Worker
767*d9f75844SAndroid Build Coastguard Worker
768*d9f75844SAndroid Build Coastguard Workerdef CheckChangeHasBugField(input_api, output_api):
769*d9f75844SAndroid Build Coastguard Worker  """Requires that the changelist is associated with a bug.
770*d9f75844SAndroid Build Coastguard Worker
771*d9f75844SAndroid Build Coastguard Worker  This check is stricter than the one in depot_tools/presubmit_canned_checks.py
772*d9f75844SAndroid Build Coastguard Worker  since it fails the presubmit if the bug field is missing or doesn't contain
773*d9f75844SAndroid Build Coastguard Worker  a bug reference.
774*d9f75844SAndroid Build Coastguard Worker
775*d9f75844SAndroid Build Coastguard Worker  This supports both 'BUG=' and 'Bug:' since we are in the process of migrating
776*d9f75844SAndroid Build Coastguard Worker  to Gerrit and it encourages the usage of 'Bug:'.
777*d9f75844SAndroid Build Coastguard Worker  """
778*d9f75844SAndroid Build Coastguard Worker  if input_api.change.BugsFromDescription():
779*d9f75844SAndroid Build Coastguard Worker    return []
780*d9f75844SAndroid Build Coastguard Worker  return [
781*d9f75844SAndroid Build Coastguard Worker      output_api.PresubmitError(
782*d9f75844SAndroid Build Coastguard Worker          'The "Bug: [bug number]" footer is mandatory. Please create a '
783*d9f75844SAndroid Build Coastguard Worker          'bug and reference it using either of:\n'
784*d9f75844SAndroid Build Coastguard Worker          ' * https://bugs.webrtc.org - reference it using Bug: '
785*d9f75844SAndroid Build Coastguard Worker          'webrtc:XXXX\n'
786*d9f75844SAndroid Build Coastguard Worker          ' * https://crbug.com - reference it using Bug: chromium:XXXXXX')
787*d9f75844SAndroid Build Coastguard Worker  ]
788*d9f75844SAndroid Build Coastguard Worker
789*d9f75844SAndroid Build Coastguard Worker
790*d9f75844SAndroid Build Coastguard Workerdef CheckJSONParseErrors(input_api, output_api, source_file_filter):
791*d9f75844SAndroid Build Coastguard Worker  """Check that JSON files do not contain syntax errors."""
792*d9f75844SAndroid Build Coastguard Worker
793*d9f75844SAndroid Build Coastguard Worker  def FilterFile(affected_file):
794*d9f75844SAndroid Build Coastguard Worker    return (input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json'
795*d9f75844SAndroid Build Coastguard Worker            and source_file_filter(affected_file))
796*d9f75844SAndroid Build Coastguard Worker
797*d9f75844SAndroid Build Coastguard Worker  def GetJSONParseError(input_api, filename):
798*d9f75844SAndroid Build Coastguard Worker    try:
799*d9f75844SAndroid Build Coastguard Worker      contents = input_api.ReadFile(filename)
800*d9f75844SAndroid Build Coastguard Worker      input_api.json.loads(contents)
801*d9f75844SAndroid Build Coastguard Worker    except ValueError as e:
802*d9f75844SAndroid Build Coastguard Worker      return e
803*d9f75844SAndroid Build Coastguard Worker    return None
804*d9f75844SAndroid Build Coastguard Worker
805*d9f75844SAndroid Build Coastguard Worker  results = []
806*d9f75844SAndroid Build Coastguard Worker  for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
807*d9f75844SAndroid Build Coastguard Worker                                               include_deletes=False):
808*d9f75844SAndroid Build Coastguard Worker    parse_error = GetJSONParseError(input_api,
809*d9f75844SAndroid Build Coastguard Worker                                    affected_file.AbsoluteLocalPath())
810*d9f75844SAndroid Build Coastguard Worker    if parse_error:
811*d9f75844SAndroid Build Coastguard Worker      results.append(
812*d9f75844SAndroid Build Coastguard Worker          output_api.PresubmitError('%s could not be parsed: %s' %
813*d9f75844SAndroid Build Coastguard Worker                                    (affected_file.LocalPath(), parse_error)))
814*d9f75844SAndroid Build Coastguard Worker  return results
815*d9f75844SAndroid Build Coastguard Worker
816*d9f75844SAndroid Build Coastguard Worker
817*d9f75844SAndroid Build Coastguard Workerdef RunPythonTests(input_api, output_api):
818*d9f75844SAndroid Build Coastguard Worker  def Join(*args):
819*d9f75844SAndroid Build Coastguard Worker    return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
820*d9f75844SAndroid Build Coastguard Worker
821*d9f75844SAndroid Build Coastguard Worker  excluded_files = [
822*d9f75844SAndroid Build Coastguard Worker      # These tests should be run manually after webrtc_dashboard_upload target
823*d9f75844SAndroid Build Coastguard Worker      # has been built.
824*d9f75844SAndroid Build Coastguard Worker      'catapult_uploader_test.py',
825*d9f75844SAndroid Build Coastguard Worker      'process_perf_results_test.py',
826*d9f75844SAndroid Build Coastguard Worker  ]
827*d9f75844SAndroid Build Coastguard Worker
828*d9f75844SAndroid Build Coastguard Worker  test_directories = [
829*d9f75844SAndroid Build Coastguard Worker      input_api.PresubmitLocalPath(),
830*d9f75844SAndroid Build Coastguard Worker      Join('rtc_tools', 'py_event_log_analyzer'),
831*d9f75844SAndroid Build Coastguard Worker      Join('audio', 'test', 'unittests'),
832*d9f75844SAndroid Build Coastguard Worker  ] + [
833*d9f75844SAndroid Build Coastguard Worker      root for root, _, files in os.walk(Join('tools_webrtc')) if any(
834*d9f75844SAndroid Build Coastguard Worker          f.endswith('_test.py') and f not in excluded_files for f in files)
835*d9f75844SAndroid Build Coastguard Worker  ]
836*d9f75844SAndroid Build Coastguard Worker
837*d9f75844SAndroid Build Coastguard Worker  tests = []
838*d9f75844SAndroid Build Coastguard Worker
839*d9f75844SAndroid Build Coastguard Worker  for directory in test_directories:
840*d9f75844SAndroid Build Coastguard Worker    tests.extend(
841*d9f75844SAndroid Build Coastguard Worker        input_api.canned_checks.GetUnitTestsInDirectory(
842*d9f75844SAndroid Build Coastguard Worker            input_api,
843*d9f75844SAndroid Build Coastguard Worker            output_api,
844*d9f75844SAndroid Build Coastguard Worker            directory,
845*d9f75844SAndroid Build Coastguard Worker            files_to_check=[r'.+_test\.py$'],
846*d9f75844SAndroid Build Coastguard Worker            run_on_python2=False))
847*d9f75844SAndroid Build Coastguard Worker  return input_api.RunTests(tests, parallel=True)
848*d9f75844SAndroid Build Coastguard Worker
849*d9f75844SAndroid Build Coastguard Worker
850*d9f75844SAndroid Build Coastguard Workerdef CheckUsageOfGoogleProtobufNamespace(input_api, output_api,
851*d9f75844SAndroid Build Coastguard Worker                                        source_file_filter):
852*d9f75844SAndroid Build Coastguard Worker  """Checks that the namespace google::protobuf has not been used."""
853*d9f75844SAndroid Build Coastguard Worker  files = []
854*d9f75844SAndroid Build Coastguard Worker  pattern = input_api.re.compile(r'google::protobuf')
855*d9f75844SAndroid Build Coastguard Worker  proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h')
856*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter(
857*d9f75844SAndroid Build Coastguard Worker      x))
858*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
859*d9f75844SAndroid Build Coastguard Worker    if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']:
860*d9f75844SAndroid Build Coastguard Worker      continue
861*d9f75844SAndroid Build Coastguard Worker    contents = input_api.ReadFile(f)
862*d9f75844SAndroid Build Coastguard Worker    if pattern.search(contents):
863*d9f75844SAndroid Build Coastguard Worker      files.append(f)
864*d9f75844SAndroid Build Coastguard Worker
865*d9f75844SAndroid Build Coastguard Worker  if files:
866*d9f75844SAndroid Build Coastguard Worker    return [
867*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
868*d9f75844SAndroid Build Coastguard Worker            'Please avoid to use namespace `google::protobuf` directly.\n'
869*d9f75844SAndroid Build Coastguard Worker            'Add a using directive in `%s` and include that header instead.' %
870*d9f75844SAndroid Build Coastguard Worker            proto_utils_path, files)
871*d9f75844SAndroid Build Coastguard Worker    ]
872*d9f75844SAndroid Build Coastguard Worker  return []
873*d9f75844SAndroid Build Coastguard Worker
874*d9f75844SAndroid Build Coastguard Worker
875*d9f75844SAndroid Build Coastguard Workerdef _LicenseHeader(input_api):
876*d9f75844SAndroid Build Coastguard Worker  """Returns the license header regexp."""
877*d9f75844SAndroid Build Coastguard Worker  # Accept any year number from 2003 to the current year
878*d9f75844SAndroid Build Coastguard Worker  current_year = int(input_api.time.strftime('%Y'))
879*d9f75844SAndroid Build Coastguard Worker  allowed_years = (str(s) for s in reversed(range(2003, current_year + 1)))
880*d9f75844SAndroid Build Coastguard Worker  years_re = '(' + '|'.join(allowed_years) + ')'
881*d9f75844SAndroid Build Coastguard Worker  license_header = (
882*d9f75844SAndroid Build Coastguard Worker      r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
883*d9f75844SAndroid Build Coastguard Worker      r'All [Rr]ights [Rr]eserved\.\n'
884*d9f75844SAndroid Build Coastguard Worker      r'.*?\n'
885*d9f75844SAndroid Build Coastguard Worker      r'.*? Use of this source code is governed by a BSD-style license\n'
886*d9f75844SAndroid Build Coastguard Worker      r'.*? that can be found in the LICENSE file in the root of the source\n'
887*d9f75844SAndroid Build Coastguard Worker      r'.*? tree\. An additional intellectual property rights grant can be '
888*d9f75844SAndroid Build Coastguard Worker      r'found\n'
889*d9f75844SAndroid Build Coastguard Worker      r'.*? in the file PATENTS\.  All contributing project authors may\n'
890*d9f75844SAndroid Build Coastguard Worker      r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
891*d9f75844SAndroid Build Coastguard Worker  ) % {
892*d9f75844SAndroid Build Coastguard Worker      'year': years_re,
893*d9f75844SAndroid Build Coastguard Worker  }
894*d9f75844SAndroid Build Coastguard Worker  return license_header
895*d9f75844SAndroid Build Coastguard Worker
896*d9f75844SAndroid Build Coastguard Worker
897*d9f75844SAndroid Build Coastguard Workerdef CommonChecks(input_api, output_api):
898*d9f75844SAndroid Build Coastguard Worker  """Checks common to both upload and commit."""
899*d9f75844SAndroid Build Coastguard Worker  results = []
900*d9f75844SAndroid Build Coastguard Worker  # Filter out files that are in objc or ios dirs from being cpplint-ed since
901*d9f75844SAndroid Build Coastguard Worker  # they do not follow C++ lint rules.
902*d9f75844SAndroid Build Coastguard Worker  exception_list = input_api.DEFAULT_FILES_TO_SKIP + (
903*d9f75844SAndroid Build Coastguard Worker      r".*\bobjc[\\\/].*",
904*d9f75844SAndroid Build Coastguard Worker      r".*objc\.[hcm]+$",
905*d9f75844SAndroid Build Coastguard Worker  )
906*d9f75844SAndroid Build Coastguard Worker  source_file_filter = lambda x: input_api.FilterSourceFile(
907*d9f75844SAndroid Build Coastguard Worker      x, None, exception_list)
908*d9f75844SAndroid Build Coastguard Worker  results.extend(
909*d9f75844SAndroid Build Coastguard Worker      CheckApprovedFilesLintClean(input_api, output_api, source_file_filter))
910*d9f75844SAndroid Build Coastguard Worker  results.extend(
911*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckLicense(input_api, output_api,
912*d9f75844SAndroid Build Coastguard Worker                                           _LicenseHeader(input_api)))
913*d9f75844SAndroid Build Coastguard Worker
914*d9f75844SAndroid Build Coastguard Worker  # TODO(bugs.webrtc.org/12114): Delete this filter and run pylint on
915*d9f75844SAndroid Build Coastguard Worker  # all python files. This is a temporary solution.
916*d9f75844SAndroid Build Coastguard Worker  python_file_filter = lambda f: (f.LocalPath().endswith('.py') and
917*d9f75844SAndroid Build Coastguard Worker                                  source_file_filter(f))
918*d9f75844SAndroid Build Coastguard Worker  python_changed_files = [
919*d9f75844SAndroid Build Coastguard Worker      f.LocalPath()
920*d9f75844SAndroid Build Coastguard Worker      for f in input_api.AffectedFiles(include_deletes=False,
921*d9f75844SAndroid Build Coastguard Worker                                       file_filter=python_file_filter)
922*d9f75844SAndroid Build Coastguard Worker  ]
923*d9f75844SAndroid Build Coastguard Worker
924*d9f75844SAndroid Build Coastguard Worker  results.extend(
925*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.RunPylint(
926*d9f75844SAndroid Build Coastguard Worker          input_api,
927*d9f75844SAndroid Build Coastguard Worker          output_api,
928*d9f75844SAndroid Build Coastguard Worker          files_to_check=python_changed_files,
929*d9f75844SAndroid Build Coastguard Worker          files_to_skip=(
930*d9f75844SAndroid Build Coastguard Worker              r'^base[\\\/].*\.py$',
931*d9f75844SAndroid Build Coastguard Worker              r'^build[\\\/].*\.py$',
932*d9f75844SAndroid Build Coastguard Worker              r'^buildtools[\\\/].*\.py$',
933*d9f75844SAndroid Build Coastguard Worker              r'^infra[\\\/].*\.py$',
934*d9f75844SAndroid Build Coastguard Worker              r'^ios[\\\/].*\.py$',
935*d9f75844SAndroid Build Coastguard Worker              r'^out.*[\\\/].*\.py$',
936*d9f75844SAndroid Build Coastguard Worker              r'^testing[\\\/].*\.py$',
937*d9f75844SAndroid Build Coastguard Worker              r'^third_party[\\\/].*\.py$',
938*d9f75844SAndroid Build Coastguard Worker              r'^tools[\\\/].*\.py$',
939*d9f75844SAndroid Build Coastguard Worker              r'^xcodebuild.*[\\\/].*\.py$',
940*d9f75844SAndroid Build Coastguard Worker          ),
941*d9f75844SAndroid Build Coastguard Worker          pylintrc='pylintrc',
942*d9f75844SAndroid Build Coastguard Worker          version='2.7'))
943*d9f75844SAndroid Build Coastguard Worker
944*d9f75844SAndroid Build Coastguard Worker  # TODO(bugs.webrtc.org/13606): talk/ is no more, so make below checks simpler?
945*d9f75844SAndroid Build Coastguard Worker  # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function
946*d9f75844SAndroid Build Coastguard Worker  # since we need to have different license checks
947*d9f75844SAndroid Build Coastguard Worker  # in talk/ and webrtc/directories.
948*d9f75844SAndroid Build Coastguard Worker  # Instead, hand-picked checks are included below.
949*d9f75844SAndroid Build Coastguard Worker
950*d9f75844SAndroid Build Coastguard Worker  # .m and .mm files are ObjC files. For simplicity we will consider
951*d9f75844SAndroid Build Coastguard Worker  # .h files in ObjC subdirectories ObjC headers.
952*d9f75844SAndroid Build Coastguard Worker  objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$')
953*d9f75844SAndroid Build Coastguard Worker  # Skip long-lines check for DEPS and GN files.
954*d9f75844SAndroid Build Coastguard Worker  build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
955*d9f75844SAndroid Build Coastguard Worker  # Also we will skip most checks for third_party directory.
956*d9f75844SAndroid Build Coastguard Worker  third_party_filter_list = (r'(^|.*[\\\/])third_party[\\\/].+', )
957*d9f75844SAndroid Build Coastguard Worker  eighty_char_sources = lambda x: input_api.FilterSourceFile(
958*d9f75844SAndroid Build Coastguard Worker      x,
959*d9f75844SAndroid Build Coastguard Worker      files_to_skip=build_file_filter_list + objc_filter_list +
960*d9f75844SAndroid Build Coastguard Worker      third_party_filter_list)
961*d9f75844SAndroid Build Coastguard Worker  hundred_char_sources = lambda x: input_api.FilterSourceFile(
962*d9f75844SAndroid Build Coastguard Worker      x, files_to_check=objc_filter_list)
963*d9f75844SAndroid Build Coastguard Worker  non_third_party_sources = lambda x: input_api.FilterSourceFile(
964*d9f75844SAndroid Build Coastguard Worker      x, files_to_skip=third_party_filter_list)
965*d9f75844SAndroid Build Coastguard Worker
966*d9f75844SAndroid Build Coastguard Worker  results.extend(
967*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckLongLines(
968*d9f75844SAndroid Build Coastguard Worker          input_api,
969*d9f75844SAndroid Build Coastguard Worker          output_api,
970*d9f75844SAndroid Build Coastguard Worker          maxlen=80,
971*d9f75844SAndroid Build Coastguard Worker          source_file_filter=eighty_char_sources))
972*d9f75844SAndroid Build Coastguard Worker  results.extend(
973*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckLongLines(
974*d9f75844SAndroid Build Coastguard Worker          input_api,
975*d9f75844SAndroid Build Coastguard Worker          output_api,
976*d9f75844SAndroid Build Coastguard Worker          maxlen=100,
977*d9f75844SAndroid Build Coastguard Worker          source_file_filter=hundred_char_sources))
978*d9f75844SAndroid Build Coastguard Worker  results.extend(
979*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckChangeHasNoTabs(
980*d9f75844SAndroid Build Coastguard Worker          input_api, output_api, source_file_filter=non_third_party_sources))
981*d9f75844SAndroid Build Coastguard Worker  results.extend(
982*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
983*d9f75844SAndroid Build Coastguard Worker          input_api, output_api, source_file_filter=non_third_party_sources))
984*d9f75844SAndroid Build Coastguard Worker  results.extend(
985*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckAuthorizedAuthor(
986*d9f75844SAndroid Build Coastguard Worker          input_api,
987*d9f75844SAndroid Build Coastguard Worker          output_api,
988*d9f75844SAndroid Build Coastguard Worker          bot_allowlist=[
989*d9f75844SAndroid Build Coastguard Worker              '[email protected]',
990*d9f75844SAndroid Build Coastguard Worker              '[email protected]',
991*d9f75844SAndroid Build Coastguard Worker          ]))
992*d9f75844SAndroid Build Coastguard Worker  results.extend(
993*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckChangeTodoHasOwner(
994*d9f75844SAndroid Build Coastguard Worker          input_api, output_api, source_file_filter=non_third_party_sources))
995*d9f75844SAndroid Build Coastguard Worker  results.extend(
996*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
997*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckNativeApiHeaderChanges(input_api, output_api))
998*d9f75844SAndroid Build Coastguard Worker  results.extend(
999*d9f75844SAndroid Build Coastguard Worker      CheckNoIOStreamInHeaders(input_api,
1000*d9f75844SAndroid Build Coastguard Worker                               output_api,
1001*d9f75844SAndroid Build Coastguard Worker                               source_file_filter=non_third_party_sources))
1002*d9f75844SAndroid Build Coastguard Worker  results.extend(
1003*d9f75844SAndroid Build Coastguard Worker      CheckNoPragmaOnce(input_api,
1004*d9f75844SAndroid Build Coastguard Worker                        output_api,
1005*d9f75844SAndroid Build Coastguard Worker                        source_file_filter=non_third_party_sources))
1006*d9f75844SAndroid Build Coastguard Worker  results.extend(
1007*d9f75844SAndroid Build Coastguard Worker      CheckNoFRIEND_TEST(input_api,
1008*d9f75844SAndroid Build Coastguard Worker                         output_api,
1009*d9f75844SAndroid Build Coastguard Worker                         source_file_filter=non_third_party_sources))
1010*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckGnChanges(input_api, output_api))
1011*d9f75844SAndroid Build Coastguard Worker  results.extend(
1012*d9f75844SAndroid Build Coastguard Worker      CheckUnwantedDependencies(input_api,
1013*d9f75844SAndroid Build Coastguard Worker                                output_api,
1014*d9f75844SAndroid Build Coastguard Worker                                source_file_filter=non_third_party_sources))
1015*d9f75844SAndroid Build Coastguard Worker  results.extend(
1016*d9f75844SAndroid Build Coastguard Worker      CheckJSONParseErrors(input_api,
1017*d9f75844SAndroid Build Coastguard Worker                           output_api,
1018*d9f75844SAndroid Build Coastguard Worker                           source_file_filter=non_third_party_sources))
1019*d9f75844SAndroid Build Coastguard Worker  results.extend(RunPythonTests(input_api, output_api))
1020*d9f75844SAndroid Build Coastguard Worker  results.extend(
1021*d9f75844SAndroid Build Coastguard Worker      CheckUsageOfGoogleProtobufNamespace(
1022*d9f75844SAndroid Build Coastguard Worker          input_api, output_api, source_file_filter=non_third_party_sources))
1023*d9f75844SAndroid Build Coastguard Worker  results.extend(
1024*d9f75844SAndroid Build Coastguard Worker      CheckOrphanHeaders(input_api,
1025*d9f75844SAndroid Build Coastguard Worker                         output_api,
1026*d9f75844SAndroid Build Coastguard Worker                         source_file_filter=non_third_party_sources))
1027*d9f75844SAndroid Build Coastguard Worker  results.extend(
1028*d9f75844SAndroid Build Coastguard Worker      CheckNewlineAtTheEndOfProtoFiles(
1029*d9f75844SAndroid Build Coastguard Worker          input_api, output_api, source_file_filter=non_third_party_sources))
1030*d9f75844SAndroid Build Coastguard Worker  results.extend(
1031*d9f75844SAndroid Build Coastguard Worker      CheckNoStreamUsageIsAdded(input_api, output_api, non_third_party_sources))
1032*d9f75844SAndroid Build Coastguard Worker  results.extend(
1033*d9f75844SAndroid Build Coastguard Worker      CheckNoTestCaseUsageIsAdded(input_api, output_api,
1034*d9f75844SAndroid Build Coastguard Worker                                  non_third_party_sources))
1035*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckAddedDepsHaveTargetApprovals(input_api, output_api))
1036*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckApiDepsFileIsUpToDate(input_api, output_api))
1037*d9f75844SAndroid Build Coastguard Worker  results.extend(
1038*d9f75844SAndroid Build Coastguard Worker      CheckAbslMemoryInclude(input_api, output_api, non_third_party_sources))
1039*d9f75844SAndroid Build Coastguard Worker  results.extend(
1040*d9f75844SAndroid Build Coastguard Worker      CheckAssertUsage(input_api, output_api, non_third_party_sources))
1041*d9f75844SAndroid Build Coastguard Worker  results.extend(
1042*d9f75844SAndroid Build Coastguard Worker      CheckBannedAbslMakeUnique(input_api, output_api, non_third_party_sources))
1043*d9f75844SAndroid Build Coastguard Worker  results.extend(
1044*d9f75844SAndroid Build Coastguard Worker      CheckObjcApiSymbols(input_api, output_api, non_third_party_sources))
1045*d9f75844SAndroid Build Coastguard Worker  return results
1046*d9f75844SAndroid Build Coastguard Worker
1047*d9f75844SAndroid Build Coastguard Worker
1048*d9f75844SAndroid Build Coastguard Workerdef CheckApiDepsFileIsUpToDate(input_api, output_api):
1049*d9f75844SAndroid Build Coastguard Worker  """Check that 'include_rules' in api/DEPS is up to date.
1050*d9f75844SAndroid Build Coastguard Worker
1051*d9f75844SAndroid Build Coastguard Worker  The file api/DEPS must be kept up to date in order to avoid to avoid to
1052*d9f75844SAndroid Build Coastguard Worker  include internal header from WebRTC's api/ headers.
1053*d9f75844SAndroid Build Coastguard Worker
1054*d9f75844SAndroid Build Coastguard Worker  This check is focused on ensuring that 'include_rules' contains a deny
1055*d9f75844SAndroid Build Coastguard Worker  rule for each root level directory. More focused allow rules can be
1056*d9f75844SAndroid Build Coastguard Worker  added to 'specific_include_rules'.
1057*d9f75844SAndroid Build Coastguard Worker  """
1058*d9f75844SAndroid Build Coastguard Worker  results = []
1059*d9f75844SAndroid Build Coastguard Worker  api_deps = os.path.join(input_api.PresubmitLocalPath(), 'api', 'DEPS')
1060*d9f75844SAndroid Build Coastguard Worker  with open(api_deps) as f:
1061*d9f75844SAndroid Build Coastguard Worker    deps_content = _ParseDeps(f.read())
1062*d9f75844SAndroid Build Coastguard Worker
1063*d9f75844SAndroid Build Coastguard Worker  include_rules = deps_content.get('include_rules', [])
1064*d9f75844SAndroid Build Coastguard Worker  dirs_to_skip = set(['api', 'docs'])
1065*d9f75844SAndroid Build Coastguard Worker
1066*d9f75844SAndroid Build Coastguard Worker  # Only check top level directories affected by the current CL.
1067*d9f75844SAndroid Build Coastguard Worker  dirs_to_check = set()
1068*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles():
1069*d9f75844SAndroid Build Coastguard Worker    path_tokens = [t for t in f.LocalPath().split(os.sep) if t]
1070*d9f75844SAndroid Build Coastguard Worker    if len(path_tokens) > 1:
1071*d9f75844SAndroid Build Coastguard Worker      if (path_tokens[0] not in dirs_to_skip and os.path.isdir(
1072*d9f75844SAndroid Build Coastguard Worker          os.path.join(input_api.PresubmitLocalPath(), path_tokens[0]))):
1073*d9f75844SAndroid Build Coastguard Worker        dirs_to_check.add(path_tokens[0])
1074*d9f75844SAndroid Build Coastguard Worker
1075*d9f75844SAndroid Build Coastguard Worker  missing_include_rules = set()
1076*d9f75844SAndroid Build Coastguard Worker  for p in dirs_to_check:
1077*d9f75844SAndroid Build Coastguard Worker    rule = '-%s' % p
1078*d9f75844SAndroid Build Coastguard Worker    if rule not in include_rules:
1079*d9f75844SAndroid Build Coastguard Worker      missing_include_rules.add(rule)
1080*d9f75844SAndroid Build Coastguard Worker
1081*d9f75844SAndroid Build Coastguard Worker  if missing_include_rules:
1082*d9f75844SAndroid Build Coastguard Worker    error_msg = [
1083*d9f75844SAndroid Build Coastguard Worker        'include_rules = [\n',
1084*d9f75844SAndroid Build Coastguard Worker        '  ...\n',
1085*d9f75844SAndroid Build Coastguard Worker    ]
1086*d9f75844SAndroid Build Coastguard Worker
1087*d9f75844SAndroid Build Coastguard Worker    for r in sorted(missing_include_rules):
1088*d9f75844SAndroid Build Coastguard Worker      error_msg.append('  "%s",\n' % str(r))
1089*d9f75844SAndroid Build Coastguard Worker
1090*d9f75844SAndroid Build Coastguard Worker    error_msg.append('  ...\n')
1091*d9f75844SAndroid Build Coastguard Worker    error_msg.append(']\n')
1092*d9f75844SAndroid Build Coastguard Worker
1093*d9f75844SAndroid Build Coastguard Worker    results.append(
1094*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
1095*d9f75844SAndroid Build Coastguard Worker            'New root level directory detected! WebRTC api/ headers should '
1096*d9f75844SAndroid Build Coastguard Worker            'not #include headers from \n'
1097*d9f75844SAndroid Build Coastguard Worker            'the new directory, so please update "include_rules" in file\n'
1098*d9f75844SAndroid Build Coastguard Worker            '"%s". Example:\n%s\n' % (api_deps, ''.join(error_msg))))
1099*d9f75844SAndroid Build Coastguard Worker
1100*d9f75844SAndroid Build Coastguard Worker  return results
1101*d9f75844SAndroid Build Coastguard Worker
1102*d9f75844SAndroid Build Coastguard Worker
1103*d9f75844SAndroid Build Coastguard Workerdef CheckBannedAbslMakeUnique(input_api, output_api, source_file_filter):
1104*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) and
1105*d9f75844SAndroid Build Coastguard Worker                           source_file_filter(f))
1106*d9f75844SAndroid Build Coastguard Worker
1107*d9f75844SAndroid Build Coastguard Worker  files = []
1108*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles(include_deletes=False,
1109*d9f75844SAndroid Build Coastguard Worker                                   file_filter=file_filter):
1110*d9f75844SAndroid Build Coastguard Worker    for _, line in f.ChangedContents():
1111*d9f75844SAndroid Build Coastguard Worker      if 'absl::make_unique' in line:
1112*d9f75844SAndroid Build Coastguard Worker        files.append(f)
1113*d9f75844SAndroid Build Coastguard Worker        break
1114*d9f75844SAndroid Build Coastguard Worker
1115*d9f75844SAndroid Build Coastguard Worker  if files:
1116*d9f75844SAndroid Build Coastguard Worker    return [
1117*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
1118*d9f75844SAndroid Build Coastguard Worker            'Please use std::make_unique instead of absl::make_unique.\n'
1119*d9f75844SAndroid Build Coastguard Worker            'Affected files:', files)
1120*d9f75844SAndroid Build Coastguard Worker    ]
1121*d9f75844SAndroid Build Coastguard Worker  return []
1122*d9f75844SAndroid Build Coastguard Worker
1123*d9f75844SAndroid Build Coastguard Worker
1124*d9f75844SAndroid Build Coastguard Workerdef CheckObjcApiSymbols(input_api, output_api, source_file_filter):
1125*d9f75844SAndroid Build Coastguard Worker  rtc_objc_export = re.compile(r'RTC_OBJC_EXPORT(.|\n){26}',
1126*d9f75844SAndroid Build Coastguard Worker                               re.MULTILINE | re.DOTALL)
1127*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: (f.LocalPath().endswith(('.h')) and
1128*d9f75844SAndroid Build Coastguard Worker                           source_file_filter(f))
1129*d9f75844SAndroid Build Coastguard Worker
1130*d9f75844SAndroid Build Coastguard Worker  files = []
1131*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: (input_api.FilterSourceFile(x) and source_file_filter(
1132*d9f75844SAndroid Build Coastguard Worker      x))
1133*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
1134*d9f75844SAndroid Build Coastguard Worker    if not f.LocalPath().endswith('.h') or not 'sdk/objc' in f.LocalPath():
1135*d9f75844SAndroid Build Coastguard Worker      continue
1136*d9f75844SAndroid Build Coastguard Worker    if f.LocalPath().endswith('sdk/objc/base/RTCMacros.h'):
1137*d9f75844SAndroid Build Coastguard Worker      continue
1138*d9f75844SAndroid Build Coastguard Worker    contents = input_api.ReadFile(f)
1139*d9f75844SAndroid Build Coastguard Worker    for match in rtc_objc_export.finditer(contents):
1140*d9f75844SAndroid Build Coastguard Worker      export_block = match.group(0)
1141*d9f75844SAndroid Build Coastguard Worker      if 'RTC_OBJC_TYPE' not in export_block:
1142*d9f75844SAndroid Build Coastguard Worker        files.append(f.LocalPath())
1143*d9f75844SAndroid Build Coastguard Worker
1144*d9f75844SAndroid Build Coastguard Worker  if len(files) > 0:
1145*d9f75844SAndroid Build Coastguard Worker    return [
1146*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
1147*d9f75844SAndroid Build Coastguard Worker            'RTC_OBJC_EXPORT types must be wrapped into an RTC_OBJC_TYPE() ' +
1148*d9f75844SAndroid Build Coastguard Worker            'macro.\n\n' + 'For example:\n' +
1149*d9f75844SAndroid Build Coastguard Worker            'RTC_OBJC_EXPORT @protocol RTC_OBJC_TYPE(RtcFoo)\n\n' +
1150*d9f75844SAndroid Build Coastguard Worker            'RTC_OBJC_EXPORT @interface RTC_OBJC_TYPE(RtcFoo)\n\n' +
1151*d9f75844SAndroid Build Coastguard Worker            'Please fix the following files:', files)
1152*d9f75844SAndroid Build Coastguard Worker    ]
1153*d9f75844SAndroid Build Coastguard Worker  return []
1154*d9f75844SAndroid Build Coastguard Worker
1155*d9f75844SAndroid Build Coastguard Worker
1156*d9f75844SAndroid Build Coastguard Workerdef CheckAssertUsage(input_api, output_api, source_file_filter):
1157*d9f75844SAndroid Build Coastguard Worker  pattern = input_api.re.compile(r'\bassert\(')
1158*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h', '.m', '.mm'))
1159*d9f75844SAndroid Build Coastguard Worker                           and source_file_filter(f))
1160*d9f75844SAndroid Build Coastguard Worker
1161*d9f75844SAndroid Build Coastguard Worker  files = []
1162*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles(include_deletes=False,
1163*d9f75844SAndroid Build Coastguard Worker                                   file_filter=file_filter):
1164*d9f75844SAndroid Build Coastguard Worker    for _, line in f.ChangedContents():
1165*d9f75844SAndroid Build Coastguard Worker      if pattern.search(line):
1166*d9f75844SAndroid Build Coastguard Worker        files.append(f.LocalPath())
1167*d9f75844SAndroid Build Coastguard Worker        break
1168*d9f75844SAndroid Build Coastguard Worker
1169*d9f75844SAndroid Build Coastguard Worker  if len(files) > 0:
1170*d9f75844SAndroid Build Coastguard Worker    return [
1171*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
1172*d9f75844SAndroid Build Coastguard Worker            'Usage of assert() has been detected in the following files, '
1173*d9f75844SAndroid Build Coastguard Worker            'please use RTC_DCHECK() instead.\n Files:', files)
1174*d9f75844SAndroid Build Coastguard Worker    ]
1175*d9f75844SAndroid Build Coastguard Worker  return []
1176*d9f75844SAndroid Build Coastguard Worker
1177*d9f75844SAndroid Build Coastguard Worker
1178*d9f75844SAndroid Build Coastguard Workerdef CheckAbslMemoryInclude(input_api, output_api, source_file_filter):
1179*d9f75844SAndroid Build Coastguard Worker  pattern = input_api.re.compile(r'^#include\s*"absl/memory/memory.h"',
1180*d9f75844SAndroid Build Coastguard Worker                                 input_api.re.MULTILINE)
1181*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) and
1182*d9f75844SAndroid Build Coastguard Worker                           source_file_filter(f))
1183*d9f75844SAndroid Build Coastguard Worker
1184*d9f75844SAndroid Build Coastguard Worker  files = []
1185*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles(include_deletes=False,
1186*d9f75844SAndroid Build Coastguard Worker                                   file_filter=file_filter):
1187*d9f75844SAndroid Build Coastguard Worker    contents = input_api.ReadFile(f)
1188*d9f75844SAndroid Build Coastguard Worker    if pattern.search(contents):
1189*d9f75844SAndroid Build Coastguard Worker      continue
1190*d9f75844SAndroid Build Coastguard Worker    for _, line in f.ChangedContents():
1191*d9f75844SAndroid Build Coastguard Worker      if 'absl::WrapUnique' in line:
1192*d9f75844SAndroid Build Coastguard Worker        files.append(f)
1193*d9f75844SAndroid Build Coastguard Worker        break
1194*d9f75844SAndroid Build Coastguard Worker
1195*d9f75844SAndroid Build Coastguard Worker  if len(files) > 0:
1196*d9f75844SAndroid Build Coastguard Worker    return [
1197*d9f75844SAndroid Build Coastguard Worker        output_api.PresubmitError(
1198*d9f75844SAndroid Build Coastguard Worker            'Please include "absl/memory/memory.h" header for '
1199*d9f75844SAndroid Build Coastguard Worker            'absl::WrapUnique.\nThis header may or may not be included '
1200*d9f75844SAndroid Build Coastguard Worker            'transitively depending on the C++ standard version.', files)
1201*d9f75844SAndroid Build Coastguard Worker    ]
1202*d9f75844SAndroid Build Coastguard Worker  return []
1203*d9f75844SAndroid Build Coastguard Worker
1204*d9f75844SAndroid Build Coastguard Worker
1205*d9f75844SAndroid Build Coastguard Workerdef CheckChangeOnUpload(input_api, output_api):
1206*d9f75844SAndroid Build Coastguard Worker  results = []
1207*d9f75844SAndroid Build Coastguard Worker  results.extend(CommonChecks(input_api, output_api))
1208*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckGnGen(input_api, output_api))
1209*d9f75844SAndroid Build Coastguard Worker  results.extend(input_api.canned_checks.CheckGNFormatted(
1210*d9f75844SAndroid Build Coastguard Worker      input_api, output_api))
1211*d9f75844SAndroid Build Coastguard Worker  return results
1212*d9f75844SAndroid Build Coastguard Worker
1213*d9f75844SAndroid Build Coastguard Worker
1214*d9f75844SAndroid Build Coastguard Workerdef CheckChangeOnCommit(input_api, output_api):
1215*d9f75844SAndroid Build Coastguard Worker  results = []
1216*d9f75844SAndroid Build Coastguard Worker  results.extend(CommonChecks(input_api, output_api))
1217*d9f75844SAndroid Build Coastguard Worker  results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
1218*d9f75844SAndroid Build Coastguard Worker  results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
1219*d9f75844SAndroid Build Coastguard Worker  results.extend(
1220*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckChangeWasUploaded(input_api, output_api))
1221*d9f75844SAndroid Build Coastguard Worker  results.extend(
1222*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckChangeHasDescription(input_api, output_api))
1223*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckChangeHasBugField(input_api, output_api))
1224*d9f75844SAndroid Build Coastguard Worker  results.extend(CheckCommitMessageBugEntry(input_api, output_api))
1225*d9f75844SAndroid Build Coastguard Worker  results.extend(
1226*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.CheckTreeIsOpen(
1227*d9f75844SAndroid Build Coastguard Worker          input_api,
1228*d9f75844SAndroid Build Coastguard Worker          output_api,
1229*d9f75844SAndroid Build Coastguard Worker          json_url='http://webrtc-status.appspot.com/current?format=json'))
1230*d9f75844SAndroid Build Coastguard Worker  return results
1231*d9f75844SAndroid Build Coastguard Worker
1232*d9f75844SAndroid Build Coastguard Worker
1233*d9f75844SAndroid Build Coastguard Workerdef CheckOrphanHeaders(input_api, output_api, source_file_filter):
1234*d9f75844SAndroid Build Coastguard Worker  # We need to wait until we have an input_api object and use this
1235*d9f75844SAndroid Build Coastguard Worker  # roundabout construct to import prebubmit_checks_lib because this file is
1236*d9f75844SAndroid Build Coastguard Worker  # eval-ed and thus doesn't have __file__.
1237*d9f75844SAndroid Build Coastguard Worker  error_msg = """{} should be listed in {}."""
1238*d9f75844SAndroid Build Coastguard Worker  results = []
1239*d9f75844SAndroid Build Coastguard Worker  exempt_paths = [re.escape(os.path.join('tools_webrtc', 'ios', 'SDK'))]
1240*d9f75844SAndroid Build Coastguard Worker
1241*d9f75844SAndroid Build Coastguard Worker  with _AddToPath(
1242*d9f75844SAndroid Build Coastguard Worker      input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools_webrtc',
1243*d9f75844SAndroid Build Coastguard Worker                             'presubmit_checks_lib')):
1244*d9f75844SAndroid Build Coastguard Worker    from check_orphan_headers import GetBuildGnPathFromFilePath
1245*d9f75844SAndroid Build Coastguard Worker    from check_orphan_headers import IsHeaderInBuildGn
1246*d9f75844SAndroid Build Coastguard Worker
1247*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: input_api.FilterSourceFile(
1248*d9f75844SAndroid Build Coastguard Worker      x, files_to_skip=exempt_paths) and source_file_filter(x)
1249*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
1250*d9f75844SAndroid Build Coastguard Worker    if f.LocalPath().endswith('.h'):
1251*d9f75844SAndroid Build Coastguard Worker      file_path = os.path.abspath(f.LocalPath())
1252*d9f75844SAndroid Build Coastguard Worker      root_dir = os.getcwd()
1253*d9f75844SAndroid Build Coastguard Worker      gn_file_path = GetBuildGnPathFromFilePath(file_path, os.path.exists,
1254*d9f75844SAndroid Build Coastguard Worker                                                root_dir)
1255*d9f75844SAndroid Build Coastguard Worker      in_build_gn = IsHeaderInBuildGn(file_path, gn_file_path)
1256*d9f75844SAndroid Build Coastguard Worker      if not in_build_gn:
1257*d9f75844SAndroid Build Coastguard Worker        results.append(
1258*d9f75844SAndroid Build Coastguard Worker            output_api.PresubmitError(
1259*d9f75844SAndroid Build Coastguard Worker                error_msg.format(f.LocalPath(), os.path.relpath(gn_file_path))))
1260*d9f75844SAndroid Build Coastguard Worker  return results
1261*d9f75844SAndroid Build Coastguard Worker
1262*d9f75844SAndroid Build Coastguard Worker
1263*d9f75844SAndroid Build Coastguard Workerdef CheckNewlineAtTheEndOfProtoFiles(input_api, output_api,
1264*d9f75844SAndroid Build Coastguard Worker                                     source_file_filter):
1265*d9f75844SAndroid Build Coastguard Worker  """Checks that all .proto files are terminated with a newline."""
1266*d9f75844SAndroid Build Coastguard Worker  error_msg = 'File {} must end with exactly one newline.'
1267*d9f75844SAndroid Build Coastguard Worker  results = []
1268*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda x: input_api.FilterSourceFile(
1269*d9f75844SAndroid Build Coastguard Worker      x, files_to_check=(r'.+\.proto$', )) and source_file_filter(x)
1270*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedSourceFiles(file_filter):
1271*d9f75844SAndroid Build Coastguard Worker    file_path = f.LocalPath()
1272*d9f75844SAndroid Build Coastguard Worker    with open(file_path) as f:
1273*d9f75844SAndroid Build Coastguard Worker      lines = f.readlines()
1274*d9f75844SAndroid Build Coastguard Worker      if len(lines) > 0 and not lines[-1].endswith('\n'):
1275*d9f75844SAndroid Build Coastguard Worker        results.append(output_api.PresubmitError(error_msg.format(file_path)))
1276*d9f75844SAndroid Build Coastguard Worker  return results
1277*d9f75844SAndroid Build Coastguard Worker
1278*d9f75844SAndroid Build Coastguard Worker
1279*d9f75844SAndroid Build Coastguard Workerdef _ExtractAddRulesFromParsedDeps(parsed_deps):
1280*d9f75844SAndroid Build Coastguard Worker  """Extract the rules that add dependencies from a parsed DEPS file.
1281*d9f75844SAndroid Build Coastguard Worker
1282*d9f75844SAndroid Build Coastguard Worker  Args:
1283*d9f75844SAndroid Build Coastguard Worker    parsed_deps: the locals dictionary from evaluating the DEPS file."""
1284*d9f75844SAndroid Build Coastguard Worker  add_rules = set()
1285*d9f75844SAndroid Build Coastguard Worker  add_rules.update([
1286*d9f75844SAndroid Build Coastguard Worker      rule[1:] for rule in parsed_deps.get('include_rules', [])
1287*d9f75844SAndroid Build Coastguard Worker      if rule.startswith('+') or rule.startswith('!')
1288*d9f75844SAndroid Build Coastguard Worker  ])
1289*d9f75844SAndroid Build Coastguard Worker  for _, rules in parsed_deps.get('specific_include_rules', {}).items():
1290*d9f75844SAndroid Build Coastguard Worker    add_rules.update([
1291*d9f75844SAndroid Build Coastguard Worker        rule[1:] for rule in rules
1292*d9f75844SAndroid Build Coastguard Worker        if rule.startswith('+') or rule.startswith('!')
1293*d9f75844SAndroid Build Coastguard Worker    ])
1294*d9f75844SAndroid Build Coastguard Worker  return add_rules
1295*d9f75844SAndroid Build Coastguard Worker
1296*d9f75844SAndroid Build Coastguard Worker
1297*d9f75844SAndroid Build Coastguard Workerdef _ParseDeps(contents):
1298*d9f75844SAndroid Build Coastguard Worker  """Simple helper for parsing DEPS files."""
1299*d9f75844SAndroid Build Coastguard Worker
1300*d9f75844SAndroid Build Coastguard Worker  # Stubs for handling special syntax in the root DEPS file.
1301*d9f75844SAndroid Build Coastguard Worker  class VarImpl:
1302*d9f75844SAndroid Build Coastguard Worker    def __init__(self, local_scope):
1303*d9f75844SAndroid Build Coastguard Worker      self._local_scope = local_scope
1304*d9f75844SAndroid Build Coastguard Worker
1305*d9f75844SAndroid Build Coastguard Worker    def Lookup(self, var_name):
1306*d9f75844SAndroid Build Coastguard Worker      """Implements the Var syntax."""
1307*d9f75844SAndroid Build Coastguard Worker      try:
1308*d9f75844SAndroid Build Coastguard Worker        return self._local_scope['vars'][var_name]
1309*d9f75844SAndroid Build Coastguard Worker      except KeyError as var_not_defined:
1310*d9f75844SAndroid Build Coastguard Worker        raise Exception('Var is not defined: %s' %
1311*d9f75844SAndroid Build Coastguard Worker                        var_name) from var_not_defined
1312*d9f75844SAndroid Build Coastguard Worker
1313*d9f75844SAndroid Build Coastguard Worker  local_scope = {}
1314*d9f75844SAndroid Build Coastguard Worker  global_scope = {
1315*d9f75844SAndroid Build Coastguard Worker      'Var': VarImpl(local_scope).Lookup,
1316*d9f75844SAndroid Build Coastguard Worker  }
1317*d9f75844SAndroid Build Coastguard Worker  exec(contents, global_scope, local_scope)
1318*d9f75844SAndroid Build Coastguard Worker  return local_scope
1319*d9f75844SAndroid Build Coastguard Worker
1320*d9f75844SAndroid Build Coastguard Worker
1321*d9f75844SAndroid Build Coastguard Workerdef _CalculateAddedDeps(os_path, old_contents, new_contents):
1322*d9f75844SAndroid Build Coastguard Worker  """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
1323*d9f75844SAndroid Build Coastguard Worker  a set of DEPS entries that we should look up.
1324*d9f75844SAndroid Build Coastguard Worker
1325*d9f75844SAndroid Build Coastguard Worker  For a directory (rather than a specific filename) we fake a path to
1326*d9f75844SAndroid Build Coastguard Worker  a specific filename by adding /DEPS. This is chosen as a file that
1327*d9f75844SAndroid Build Coastguard Worker  will seldom or never be subject to per-file include_rules.
1328*d9f75844SAndroid Build Coastguard Worker  """
1329*d9f75844SAndroid Build Coastguard Worker  # We ignore deps entries on auto-generated directories.
1330*d9f75844SAndroid Build Coastguard Worker  auto_generated_dirs = ['grit', 'jni']
1331*d9f75844SAndroid Build Coastguard Worker
1332*d9f75844SAndroid Build Coastguard Worker  old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1333*d9f75844SAndroid Build Coastguard Worker  new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1334*d9f75844SAndroid Build Coastguard Worker
1335*d9f75844SAndroid Build Coastguard Worker  added_deps = new_deps.difference(old_deps)
1336*d9f75844SAndroid Build Coastguard Worker
1337*d9f75844SAndroid Build Coastguard Worker  results = set()
1338*d9f75844SAndroid Build Coastguard Worker  for added_dep in added_deps:
1339*d9f75844SAndroid Build Coastguard Worker    if added_dep.split('/')[0] in auto_generated_dirs:
1340*d9f75844SAndroid Build Coastguard Worker      continue
1341*d9f75844SAndroid Build Coastguard Worker    # Assume that a rule that ends in .h is a rule for a specific file.
1342*d9f75844SAndroid Build Coastguard Worker    if added_dep.endswith('.h'):
1343*d9f75844SAndroid Build Coastguard Worker      results.add(added_dep)
1344*d9f75844SAndroid Build Coastguard Worker    else:
1345*d9f75844SAndroid Build Coastguard Worker      results.add(os_path.join(added_dep, 'DEPS'))
1346*d9f75844SAndroid Build Coastguard Worker  return results
1347*d9f75844SAndroid Build Coastguard Worker
1348*d9f75844SAndroid Build Coastguard Worker
1349*d9f75844SAndroid Build Coastguard Workerdef CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1350*d9f75844SAndroid Build Coastguard Worker  """When a dependency prefixed with + is added to a DEPS file, we
1351*d9f75844SAndroid Build Coastguard Worker    want to make sure that the change is reviewed by an OWNER of the
1352*d9f75844SAndroid Build Coastguard Worker    target file or directory, to avoid layering violations from being
1353*d9f75844SAndroid Build Coastguard Worker    introduced. This check verifies that this happens.
1354*d9f75844SAndroid Build Coastguard Worker    """
1355*d9f75844SAndroid Build Coastguard Worker  virtual_depended_on_files = set()
1356*d9f75844SAndroid Build Coastguard Worker
1357*d9f75844SAndroid Build Coastguard Worker  file_filter = lambda f: not input_api.re.match(
1358*d9f75844SAndroid Build Coastguard Worker      r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
1359*d9f75844SAndroid Build Coastguard Worker  for f in input_api.AffectedFiles(include_deletes=False,
1360*d9f75844SAndroid Build Coastguard Worker                                   file_filter=file_filter):
1361*d9f75844SAndroid Build Coastguard Worker    filename = input_api.os_path.basename(f.LocalPath())
1362*d9f75844SAndroid Build Coastguard Worker    if filename == 'DEPS':
1363*d9f75844SAndroid Build Coastguard Worker      virtual_depended_on_files.update(
1364*d9f75844SAndroid Build Coastguard Worker          _CalculateAddedDeps(input_api.os_path, '\n'.join(f.OldContents()),
1365*d9f75844SAndroid Build Coastguard Worker                              '\n'.join(f.NewContents())))
1366*d9f75844SAndroid Build Coastguard Worker
1367*d9f75844SAndroid Build Coastguard Worker  if not virtual_depended_on_files:
1368*d9f75844SAndroid Build Coastguard Worker    return []
1369*d9f75844SAndroid Build Coastguard Worker
1370*d9f75844SAndroid Build Coastguard Worker  if input_api.is_committing:
1371*d9f75844SAndroid Build Coastguard Worker    if input_api.tbr:
1372*d9f75844SAndroid Build Coastguard Worker      return [
1373*d9f75844SAndroid Build Coastguard Worker          output_api.PresubmitNotifyResult(
1374*d9f75844SAndroid Build Coastguard Worker              '--tbr was specified, skipping OWNERS check for DEPS '
1375*d9f75844SAndroid Build Coastguard Worker              'additions')
1376*d9f75844SAndroid Build Coastguard Worker      ]
1377*d9f75844SAndroid Build Coastguard Worker    if input_api.dry_run:
1378*d9f75844SAndroid Build Coastguard Worker      return [
1379*d9f75844SAndroid Build Coastguard Worker          output_api.PresubmitNotifyResult(
1380*d9f75844SAndroid Build Coastguard Worker              'This is a dry run, skipping OWNERS check for DEPS '
1381*d9f75844SAndroid Build Coastguard Worker              'additions')
1382*d9f75844SAndroid Build Coastguard Worker      ]
1383*d9f75844SAndroid Build Coastguard Worker    if not input_api.change.issue:
1384*d9f75844SAndroid Build Coastguard Worker      return [
1385*d9f75844SAndroid Build Coastguard Worker          output_api.PresubmitError(
1386*d9f75844SAndroid Build Coastguard Worker              "DEPS approval by OWNERS check failed: this change has "
1387*d9f75844SAndroid Build Coastguard Worker              "no change number, so we can't check it for approvals.")
1388*d9f75844SAndroid Build Coastguard Worker      ]
1389*d9f75844SAndroid Build Coastguard Worker    output = output_api.PresubmitError
1390*d9f75844SAndroid Build Coastguard Worker  else:
1391*d9f75844SAndroid Build Coastguard Worker    output = output_api.PresubmitNotifyResult
1392*d9f75844SAndroid Build Coastguard Worker
1393*d9f75844SAndroid Build Coastguard Worker  owner_email, reviewers = (
1394*d9f75844SAndroid Build Coastguard Worker      input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1395*d9f75844SAndroid Build Coastguard Worker          input_api, None, approval_needed=input_api.is_committing))
1396*d9f75844SAndroid Build Coastguard Worker
1397*d9f75844SAndroid Build Coastguard Worker  owner_email = owner_email or input_api.change.author_email
1398*d9f75844SAndroid Build Coastguard Worker
1399*d9f75844SAndroid Build Coastguard Worker  approval_status = input_api.owners_client.GetFilesApprovalStatus(
1400*d9f75844SAndroid Build Coastguard Worker      virtual_depended_on_files, reviewers.union([owner_email]), [])
1401*d9f75844SAndroid Build Coastguard Worker  missing_files = [
1402*d9f75844SAndroid Build Coastguard Worker      f for f in virtual_depended_on_files
1403*d9f75844SAndroid Build Coastguard Worker      if approval_status[f] != input_api.owners_client.APPROVED
1404*d9f75844SAndroid Build Coastguard Worker  ]
1405*d9f75844SAndroid Build Coastguard Worker
1406*d9f75844SAndroid Build Coastguard Worker  # We strip the /DEPS part that was added by
1407*d9f75844SAndroid Build Coastguard Worker  # _FilesToCheckForIncomingDeps to fake a path to a file in a
1408*d9f75844SAndroid Build Coastguard Worker  # directory.
1409*d9f75844SAndroid Build Coastguard Worker  def StripDeps(path):
1410*d9f75844SAndroid Build Coastguard Worker    start_deps = path.rfind('/DEPS')
1411*d9f75844SAndroid Build Coastguard Worker    if start_deps != -1:
1412*d9f75844SAndroid Build Coastguard Worker      return path[:start_deps]
1413*d9f75844SAndroid Build Coastguard Worker    return path
1414*d9f75844SAndroid Build Coastguard Worker
1415*d9f75844SAndroid Build Coastguard Worker  unapproved_dependencies = [
1416*d9f75844SAndroid Build Coastguard Worker      "'+%s'," % StripDeps(path) for path in missing_files
1417*d9f75844SAndroid Build Coastguard Worker  ]
1418*d9f75844SAndroid Build Coastguard Worker
1419*d9f75844SAndroid Build Coastguard Worker  if unapproved_dependencies:
1420*d9f75844SAndroid Build Coastguard Worker    output_list = [
1421*d9f75844SAndroid Build Coastguard Worker        output('You need LGTM from owners of depends-on paths in DEPS that '
1422*d9f75844SAndroid Build Coastguard Worker               ' were modified in this CL:\n    %s' %
1423*d9f75844SAndroid Build Coastguard Worker               '\n    '.join(sorted(unapproved_dependencies)))
1424*d9f75844SAndroid Build Coastguard Worker    ]
1425*d9f75844SAndroid Build Coastguard Worker    suggested_owners = input_api.owners_client.SuggestOwners(
1426*d9f75844SAndroid Build Coastguard Worker        missing_files, exclude=[owner_email])
1427*d9f75844SAndroid Build Coastguard Worker    output_list.append(
1428*d9f75844SAndroid Build Coastguard Worker        output('Suggested missing target path OWNERS:\n    %s' %
1429*d9f75844SAndroid Build Coastguard Worker               '\n    '.join(suggested_owners or [])))
1430*d9f75844SAndroid Build Coastguard Worker    return output_list
1431*d9f75844SAndroid Build Coastguard Worker
1432*d9f75844SAndroid Build Coastguard Worker  return []
1433