1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159

base / PRESUBMIT.py [blame]

# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Chromium presubmit script for src/base.

See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details on the presubmit API built into depot_tools.
"""

def CheckChangeLintsClean(input_api, output_api):
  """Makes sure that the code is cpplint clean."""
  # lint_filters=[] stops the OFF_BY_DEFAULT_LINT_FILTERS from being disabled,
  # finding many more issues. verbose_level=1 finds a small number of additional
  # issues.
  # The only valid extensions for cpplint are .cc, .h, .cpp, .cu, and .ch.
  # Only process those extensions which are used in Chromium, in directories
  # that currently lint clean.
  CLEAN_CPP_FILES_ONLY = (r'base/win/.*\.(cc|h)$', )
  source_file_filter = lambda x: input_api.FilterSourceFile(
      x,
      files_to_check=CLEAN_CPP_FILES_ONLY,
      files_to_skip=input_api.DEFAULT_FILES_TO_SKIP)
  return input_api.canned_checks.CheckChangeLintsClean(
      input_api, output_api, source_file_filter=source_file_filter,
      lint_filters=[], verbose_level=1)


def _CheckNoInterfacesInBase(input_api, output_api):
  """Checks to make sure no files in libbase.a have |@interface|."""
  pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE)
  files = []
  for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
    if (f.LocalPath().startswith('base/') and
        not "/ios/" in f.LocalPath() and
        not "/test/" in f.LocalPath() and
        not f.LocalPath().endswith('.java') and
        not f.LocalPath().endswith('_unittest.mm') and
        not f.LocalPath().endswith('_spi.h')):
      contents = input_api.ReadFile(f)
      if pattern.search(contents):
        files.append(f)

  if len(files):
    return [ output_api.PresubmitError(
        'Objective-C interfaces or categories are forbidden in libbase. ' +
        'See http://groups.google.com/a/chromium.org/group/chromium-dev/' +
        'browse_thread/thread/efb28c10435987fd',
        files) ]
  return []


def _FindLocations(input_api, search_regexes, files_to_check, files_to_skip):
  """Returns locations matching one of the search_regexes."""
  def FilterFile(affected_file):
    return input_api.FilterSourceFile(
      affected_file,
      files_to_check=files_to_check,
      files_to_skip=files_to_skip)

  no_presubmit = r"// no-presubmit-check"
  locations = []
  for f in input_api.AffectedSourceFiles(FilterFile):
    for line_num, line in f.ChangedContents():
      for search_regex in search_regexes:
        if (input_api.re.search(search_regex, line) and
            not input_api.re.search(no_presubmit, line)):
          locations.append("    %s:%d" % (f.LocalPath(), line_num))
          break
  return locations


def _CheckNoTraceEventInclude(input_api, output_api):
  """Verify that //base includes base_tracing.h instead of trace event headers.

  Checks that files outside trace event implementation include the
  base_tracing.h header instead of specific trace event implementation headers
  to maintain compatibility with the gn flag "enable_base_tracing = false".
  """
  discouraged_includes = [
    r'^#include "base/trace_event/(?!base_tracing\.h|base_tracing_forward\.h)',
    r'^#include "third_party/perfetto/include/',
  ]

  files_to_check = [
    r".*\.(h|cc|mm)$",
  ]
  files_to_skip = [
    r".*/test/.*",
    r".*/trace_event/.*",
    r".*/tracing/.*",
  ]

  locations = _FindLocations(input_api, discouraged_includes, files_to_check,
                             files_to_skip)
  if locations:
    return [ output_api.PresubmitError(
        'Base code should include "base/trace_event/base_tracing.h" instead\n' +
        'of trace_event implementation headers. If you need to include an\n' +
        'implementation header, verify that "gn check" and base_unittests\n' +
        'still pass with gn arg "enable_base_tracing = false" and add\n' +
        '"// no-presubmit-check" after the include. \n' +
        '\n'.join(locations)) ]
  return []


def _WarnPbzeroIncludes(input_api, output_api):
  """Warn to check enable_base_tracing=false when including a pbzero header.

  Emits a warning when including a perfetto pbzero header, encouraging the
  user to verify that //base still builds with enable_base_tracing=false.
  """
  warn_includes = [
    r'^#include "third_party/perfetto/protos/',
    r'^#include "base/tracing/protos/',
  ]

  files_to_check = [
    r".*\.(h|cc|mm)$",
  ]
  files_to_skip = [
    r".*/test/.*",
    r".*/trace_event/.*",
    r".*/tracing/.*",
  ]

  locations = _FindLocations(input_api, warn_includes, files_to_check,
                             files_to_skip)
  if locations:
    return [ output_api.PresubmitPromptWarning(
        'Please verify that "gn check" and base_unittests still pass with\n' +
        'gn arg "enable_base_tracing = false" when adding typed trace\n' +
        'events to //base. You can use "#if BUILDFLAG(ENABLE_BASE_TRACING)"\n' +
        'to exclude pbzero headers and anything not supported by\n' +
        '//base/trace_event/trace_event_stub.h.\n' +
        '\n'.join(locations)) ]
  return []


def _CommonChecks(input_api, output_api):
  """Checks common to both upload and commit."""
  results = []
  results.extend(_CheckNoInterfacesInBase(input_api, output_api))
  results.extend(_CheckNoTraceEventInclude(input_api, output_api))
  results.extend(_WarnPbzeroIncludes(input_api, output_api))
  results.extend(CheckChangeLintsClean(input_api, output_api))
  return results


def CheckChangeOnUpload(input_api, output_api):
  results = []
  results.extend(_CommonChecks(input_api, output_api))
  return results


def CheckChangeOnCommit(input_api, output_api):
  results = []
  results.extend(_CommonChecks(input_api, output_api))
  return results