11cb0ef41Sopenharmony_ci#!/usr/bin/env python
21cb0ef41Sopenharmony_ci#
31cb0ef41Sopenharmony_ci# Copyright 2018 the V8 project authors. All rights reserved.
41cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
51cb0ef41Sopenharmony_ci# found in the LICENSE file.
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci# for py2/py3 compatibility
81cb0ef41Sopenharmony_cifrom __future__ import print_function
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciimport json
111cb0ef41Sopenharmony_ciimport multiprocessing
121cb0ef41Sopenharmony_ciimport optparse
131cb0ef41Sopenharmony_ciimport os
141cb0ef41Sopenharmony_ciimport re
151cb0ef41Sopenharmony_ciimport subprocess
161cb0ef41Sopenharmony_ciimport sys
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciCLANG_TIDY_WARNING = re.compile(r'(\/.*?)\ .*\[(.*)\]$')
191cb0ef41Sopenharmony_ciCLANG_TIDY_CMDLINE_OUT = re.compile(r'^clang-tidy.*\ .*|^\./\.\*')
201cb0ef41Sopenharmony_ciFILE_REGEXS = ['../src/*', '../test/*']
211cb0ef41Sopenharmony_ciHEADER_REGEX = ['\.\.\/src\/.*|\.\.\/include\/.*|\.\.\/test\/.*']
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciTHREADS = multiprocessing.cpu_count()
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ciclass ClangTidyWarning(object):
271cb0ef41Sopenharmony_ci  """
281cb0ef41Sopenharmony_ci  Wraps up a clang-tidy warning to present aggregated information.
291cb0ef41Sopenharmony_ci  """
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  def __init__(self, warning_type):
321cb0ef41Sopenharmony_ci    self.warning_type = warning_type
331cb0ef41Sopenharmony_ci    self.occurrences = set()
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  def add_occurrence(self, file_path):
361cb0ef41Sopenharmony_ci    self.occurrences.add(file_path.lstrip())
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  def __hash__(self):
391cb0ef41Sopenharmony_ci    return hash(self.warning_type)
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  def to_string(self, file_loc):
421cb0ef41Sopenharmony_ci    s = '[%s] #%d\n' % (self.warning_type, len(self.occurrences))
431cb0ef41Sopenharmony_ci    if file_loc:
441cb0ef41Sopenharmony_ci      s += ' ' + '\n  '.join(self.occurrences)
451cb0ef41Sopenharmony_ci      s += '\n'
461cb0ef41Sopenharmony_ci    return s
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  def __str__(self):
491cb0ef41Sopenharmony_ci    return self.to_string(False)
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  def __lt__(self, other):
521cb0ef41Sopenharmony_ci    return len(self.occurrences) < len(other.occurrences)
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cidef GenerateCompileCommands(build_folder):
561cb0ef41Sopenharmony_ci  """
571cb0ef41Sopenharmony_ci  Generate a compilation database.
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  Currently clang-tidy-4 does not understand all flags that are passed
601cb0ef41Sopenharmony_ci  by the build system, therefore, we remove them from the generated file.
611cb0ef41Sopenharmony_ci  """
621cb0ef41Sopenharmony_ci  ninja_ps = subprocess.Popen(
631cb0ef41Sopenharmony_ci    ['ninja', '-t', 'compdb', 'cxx', 'cc'],
641cb0ef41Sopenharmony_ci    stdout=subprocess.PIPE,
651cb0ef41Sopenharmony_ci    cwd=build_folder)
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  out_filepath = os.path.join(build_folder, 'compile_commands.json')
681cb0ef41Sopenharmony_ci  with open(out_filepath, 'w') as cc_file:
691cb0ef41Sopenharmony_ci    while True:
701cb0ef41Sopenharmony_ci        line = ninja_ps.stdout.readline()
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci        if line == '':
731cb0ef41Sopenharmony_ci            break
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci        line = line.replace('-fcomplete-member-pointers', '')
761cb0ef41Sopenharmony_ci        line = line.replace('-Wno-enum-compare-switch', '')
771cb0ef41Sopenharmony_ci        line = line.replace('-Wno-ignored-pragma-optimize', '')
781cb0ef41Sopenharmony_ci        line = line.replace('-Wno-null-pointer-arithmetic', '')
791cb0ef41Sopenharmony_ci        line = line.replace('-Wno-unused-lambda-capture', '')
801cb0ef41Sopenharmony_ci        line = line.replace('-Wno-defaulted-function-deleted', '')
811cb0ef41Sopenharmony_ci        cc_file.write(line)
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_cidef skip_line(line):
851cb0ef41Sopenharmony_ci  """
861cb0ef41Sopenharmony_ci  Check if a clang-tidy output line should be skipped.
871cb0ef41Sopenharmony_ci  """
881cb0ef41Sopenharmony_ci  return bool(CLANG_TIDY_CMDLINE_OUT.search(line))
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_cidef ClangTidyRunFull(build_folder, skip_output_filter, checks, auto_fix):
921cb0ef41Sopenharmony_ci  """
931cb0ef41Sopenharmony_ci  Run clang-tidy on the full codebase and print warnings.
941cb0ef41Sopenharmony_ci  """
951cb0ef41Sopenharmony_ci  extra_args = []
961cb0ef41Sopenharmony_ci  if auto_fix:
971cb0ef41Sopenharmony_ci    extra_args.append('-fix')
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  if checks is not None:
1001cb0ef41Sopenharmony_ci    extra_args.append('-checks')
1011cb0ef41Sopenharmony_ci    extra_args.append('-*, ' + checks)
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  with open(os.devnull, 'w') as DEVNULL:
1041cb0ef41Sopenharmony_ci    ct_process = subprocess.Popen(
1051cb0ef41Sopenharmony_ci      ['run-clang-tidy', '-j' + str(THREADS), '-p', '.']
1061cb0ef41Sopenharmony_ci       + ['-header-filter'] + HEADER_REGEX + extra_args
1071cb0ef41Sopenharmony_ci       + FILE_REGEXS,
1081cb0ef41Sopenharmony_ci      cwd=build_folder,
1091cb0ef41Sopenharmony_ci      stdout=subprocess.PIPE,
1101cb0ef41Sopenharmony_ci      stderr=DEVNULL)
1111cb0ef41Sopenharmony_ci  removing_check_header = False
1121cb0ef41Sopenharmony_ci  empty_lines = 0
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  while True:
1151cb0ef41Sopenharmony_ci    line = ct_process.stdout.readline()
1161cb0ef41Sopenharmony_ci    if line == '':
1171cb0ef41Sopenharmony_ci      break
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    # Skip all lines after Enbale checks and before two newlines,
1201cb0ef41Sopenharmony_ci    # i.e., skip clang-tidy check list.
1211cb0ef41Sopenharmony_ci    if line.startswith('Enabled checks'):
1221cb0ef41Sopenharmony_ci      removing_check_header = True
1231cb0ef41Sopenharmony_ci    if removing_check_header and not skip_output_filter:
1241cb0ef41Sopenharmony_ci      if line == '\n':
1251cb0ef41Sopenharmony_ci        empty_lines += 1
1261cb0ef41Sopenharmony_ci      if empty_lines == 2:
1271cb0ef41Sopenharmony_ci        removing_check_header = False
1281cb0ef41Sopenharmony_ci      continue
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci    # Different lines get removed to ease output reading.
1311cb0ef41Sopenharmony_ci    if not skip_output_filter and skip_line(line):
1321cb0ef41Sopenharmony_ci      continue
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    # Print line, because no filter was matched.
1351cb0ef41Sopenharmony_ci    if line != '\n':
1361cb0ef41Sopenharmony_ci        sys.stdout.write(line)
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_cidef ClangTidyRunAggregate(build_folder, print_files):
1401cb0ef41Sopenharmony_ci  """
1411cb0ef41Sopenharmony_ci  Run clang-tidy on the full codebase and aggregate warnings into categories.
1421cb0ef41Sopenharmony_ci  """
1431cb0ef41Sopenharmony_ci  with open(os.devnull, 'w') as DEVNULL:
1441cb0ef41Sopenharmony_ci    ct_process = subprocess.Popen(
1451cb0ef41Sopenharmony_ci      ['run-clang-tidy', '-j' + str(THREADS), '-p', '.'] +
1461cb0ef41Sopenharmony_ci        ['-header-filter'] + HEADER_REGEX +
1471cb0ef41Sopenharmony_ci        FILE_REGEXS,
1481cb0ef41Sopenharmony_ci      cwd=build_folder,
1491cb0ef41Sopenharmony_ci      stdout=subprocess.PIPE,
1501cb0ef41Sopenharmony_ci      stderr=DEVNULL)
1511cb0ef41Sopenharmony_ci  warnings = dict()
1521cb0ef41Sopenharmony_ci  while True:
1531cb0ef41Sopenharmony_ci    line = ct_process.stdout.readline()
1541cb0ef41Sopenharmony_ci    if line == '':
1551cb0ef41Sopenharmony_ci      break
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    res = CLANG_TIDY_WARNING.search(line)
1581cb0ef41Sopenharmony_ci    if res is not None:
1591cb0ef41Sopenharmony_ci      warnings.setdefault(
1601cb0ef41Sopenharmony_ci          res.group(2),
1611cb0ef41Sopenharmony_ci          ClangTidyWarning(res.group(2))).add_occurrence(res.group(1))
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  for warning in sorted(warnings.values(), reverse=True):
1641cb0ef41Sopenharmony_ci    sys.stdout.write(warning.to_string(print_files))
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_cidef ClangTidyRunDiff(build_folder, diff_branch, auto_fix):
1681cb0ef41Sopenharmony_ci  """
1691cb0ef41Sopenharmony_ci  Run clang-tidy on the diff between current and the diff_branch.
1701cb0ef41Sopenharmony_ci  """
1711cb0ef41Sopenharmony_ci  if diff_branch is None:
1721cb0ef41Sopenharmony_ci    diff_branch = subprocess.check_output(['git', 'merge-base',
1731cb0ef41Sopenharmony_ci                                           'HEAD', 'origin/master']).strip()
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci  git_ps = subprocess.Popen(
1761cb0ef41Sopenharmony_ci    ['git', 'diff', '-U0', diff_branch], stdout=subprocess.PIPE)
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  extra_args = []
1791cb0ef41Sopenharmony_ci  if auto_fix:
1801cb0ef41Sopenharmony_ci    extra_args.append('-fix')
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  with open(os.devnull, 'w') as DEVNULL:
1831cb0ef41Sopenharmony_ci    """
1841cb0ef41Sopenharmony_ci    The script `clang-tidy-diff` does not provide support to add header-
1851cb0ef41Sopenharmony_ci    filters. To still analyze headers we use the build path option `-path` to
1861cb0ef41Sopenharmony_ci    inject our header-filter option. This works because the script just adds
1871cb0ef41Sopenharmony_ci    the passed path string to the commandline of clang-tidy.
1881cb0ef41Sopenharmony_ci    """
1891cb0ef41Sopenharmony_ci    modified_build_folder = build_folder
1901cb0ef41Sopenharmony_ci    modified_build_folder += ' -header-filter='
1911cb0ef41Sopenharmony_ci    modified_build_folder += '\'' + ''.join(HEADER_REGEX) + '\''
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci    ct_ps = subprocess.Popen(
1941cb0ef41Sopenharmony_ci      ['clang-tidy-diff.py', '-path', modified_build_folder, '-p1'] +
1951cb0ef41Sopenharmony_ci        extra_args,
1961cb0ef41Sopenharmony_ci      stdin=git_ps.stdout,
1971cb0ef41Sopenharmony_ci      stdout=subprocess.PIPE,
1981cb0ef41Sopenharmony_ci      stderr=DEVNULL)
1991cb0ef41Sopenharmony_ci  git_ps.wait()
2001cb0ef41Sopenharmony_ci  while True:
2011cb0ef41Sopenharmony_ci    line = ct_ps.stdout.readline()
2021cb0ef41Sopenharmony_ci    if line == '':
2031cb0ef41Sopenharmony_ci      break
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci    if skip_line(line):
2061cb0ef41Sopenharmony_ci      continue
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci    sys.stdout.write(line)
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_cidef rm_prefix(string, prefix):
2121cb0ef41Sopenharmony_ci  """
2131cb0ef41Sopenharmony_ci  Removes prefix from a string until the new string
2141cb0ef41Sopenharmony_ci  no longer starts with the prefix.
2151cb0ef41Sopenharmony_ci  """
2161cb0ef41Sopenharmony_ci  while string.startswith(prefix):
2171cb0ef41Sopenharmony_ci    string = string[len(prefix):]
2181cb0ef41Sopenharmony_ci  return string
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_cidef ClangTidyRunSingleFile(build_folder, filename_to_check, auto_fix,
2221cb0ef41Sopenharmony_ci                           line_ranges=[]):
2231cb0ef41Sopenharmony_ci  """
2241cb0ef41Sopenharmony_ci  Run clang-tidy on a single file.
2251cb0ef41Sopenharmony_ci  """
2261cb0ef41Sopenharmony_ci  files_with_relative_path = []
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  compdb_filepath = os.path.join(build_folder, 'compile_commands.json')
2291cb0ef41Sopenharmony_ci  with open(compdb_filepath) as raw_json_file:
2301cb0ef41Sopenharmony_ci    compdb = json.load(raw_json_file)
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci  for db_entry in compdb:
2331cb0ef41Sopenharmony_ci    if db_entry['file'].endswith(filename_to_check):
2341cb0ef41Sopenharmony_ci      files_with_relative_path.append(db_entry['file'])
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  with open(os.devnull, 'w') as DEVNULL:
2371cb0ef41Sopenharmony_ci    for file_with_relative_path in files_with_relative_path:
2381cb0ef41Sopenharmony_ci      line_filter = None
2391cb0ef41Sopenharmony_ci      if len(line_ranges) != 0:
2401cb0ef41Sopenharmony_ci        line_filter = '['
2411cb0ef41Sopenharmony_ci        line_filter += '{ \"lines\":[' + ', '.join(line_ranges)
2421cb0ef41Sopenharmony_ci        line_filter += '], \"name\":\"'
2431cb0ef41Sopenharmony_ci        line_filter += rm_prefix(file_with_relative_path,
2441cb0ef41Sopenharmony_ci                                 '../') + '\"}'
2451cb0ef41Sopenharmony_ci        line_filter += ']'
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci      extra_args = ['-line-filter=' + line_filter] if line_filter else []
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci      if auto_fix:
2501cb0ef41Sopenharmony_ci        extra_args.append('-fix')
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci      subprocess.call(['clang-tidy', '-p', '.'] +
2531cb0ef41Sopenharmony_ci                      extra_args +
2541cb0ef41Sopenharmony_ci                      [file_with_relative_path],
2551cb0ef41Sopenharmony_ci                      cwd=build_folder,
2561cb0ef41Sopenharmony_ci                      stderr=DEVNULL)
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_cidef CheckClangTidy():
2601cb0ef41Sopenharmony_ci  """
2611cb0ef41Sopenharmony_ci  Checks if a clang-tidy binary exists.
2621cb0ef41Sopenharmony_ci  """
2631cb0ef41Sopenharmony_ci  with open(os.devnull, 'w') as DEVNULL:
2641cb0ef41Sopenharmony_ci    return subprocess.call(['which', 'clang-tidy'], stdout=DEVNULL) == 0
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_cidef CheckCompDB(build_folder):
2681cb0ef41Sopenharmony_ci  """
2691cb0ef41Sopenharmony_ci  Checks if a compilation database exists in the build_folder.
2701cb0ef41Sopenharmony_ci  """
2711cb0ef41Sopenharmony_ci  return os.path.isfile(os.path.join(build_folder, 'compile_commands.json'))
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_cidef DetectBuildFolder():
2751cb0ef41Sopenharmony_ci    """
2761cb0ef41Sopenharmony_ci    Tries to auto detect the last used build folder in out/
2771cb0ef41Sopenharmony_ci    """
2781cb0ef41Sopenharmony_ci    outdirs_folder = 'out/'
2791cb0ef41Sopenharmony_ci    last_used = None
2801cb0ef41Sopenharmony_ci    last_timestamp = -1
2811cb0ef41Sopenharmony_ci    for outdir in [outdirs_folder + folder_name
2821cb0ef41Sopenharmony_ci                   for folder_name in os.listdir(outdirs_folder)
2831cb0ef41Sopenharmony_ci                   if os.path.isdir(outdirs_folder + folder_name)]:
2841cb0ef41Sopenharmony_ci        outdir_modified_timestamp = os.path.getmtime(outdir)
2851cb0ef41Sopenharmony_ci        if  outdir_modified_timestamp > last_timestamp:
2861cb0ef41Sopenharmony_ci            last_timestamp = outdir_modified_timestamp
2871cb0ef41Sopenharmony_ci            last_used = outdir
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci    return last_used
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_cidef GetOptions():
2931cb0ef41Sopenharmony_ci  """
2941cb0ef41Sopenharmony_ci  Generate the option parser for this script.
2951cb0ef41Sopenharmony_ci  """
2961cb0ef41Sopenharmony_ci  result = optparse.OptionParser()
2971cb0ef41Sopenharmony_ci  result.add_option(
2981cb0ef41Sopenharmony_ci    '-b',
2991cb0ef41Sopenharmony_ci    '--build-folder',
3001cb0ef41Sopenharmony_ci    help='Set V8 build folder',
3011cb0ef41Sopenharmony_ci    dest='build_folder',
3021cb0ef41Sopenharmony_ci    default=None)
3031cb0ef41Sopenharmony_ci  result.add_option(
3041cb0ef41Sopenharmony_ci    '-j',
3051cb0ef41Sopenharmony_ci    help='Set the amount of threads that should be used',
3061cb0ef41Sopenharmony_ci    dest='threads',
3071cb0ef41Sopenharmony_ci    default=None)
3081cb0ef41Sopenharmony_ci  result.add_option(
3091cb0ef41Sopenharmony_ci    '--gen-compdb',
3101cb0ef41Sopenharmony_ci    help='Generate a compilation database for clang-tidy',
3111cb0ef41Sopenharmony_ci    default=False,
3121cb0ef41Sopenharmony_ci    action='store_true')
3131cb0ef41Sopenharmony_ci  result.add_option(
3141cb0ef41Sopenharmony_ci    '--no-output-filter',
3151cb0ef41Sopenharmony_ci    help='Done use any output filterning',
3161cb0ef41Sopenharmony_ci    default=False,
3171cb0ef41Sopenharmony_ci    action='store_true')
3181cb0ef41Sopenharmony_ci  result.add_option(
3191cb0ef41Sopenharmony_ci    '--fix',
3201cb0ef41Sopenharmony_ci    help='Fix auto fixable issues',
3211cb0ef41Sopenharmony_ci    default=False,
3221cb0ef41Sopenharmony_ci    dest='auto_fix',
3231cb0ef41Sopenharmony_ci    action='store_true'
3241cb0ef41Sopenharmony_ci  )
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci  # Full clang-tidy.
3271cb0ef41Sopenharmony_ci  full_run_g = optparse.OptionGroup(result, 'Clang-tidy full', '')
3281cb0ef41Sopenharmony_ci  full_run_g.add_option(
3291cb0ef41Sopenharmony_ci    '--full',
3301cb0ef41Sopenharmony_ci    help='Run clang-tidy on the whole codebase',
3311cb0ef41Sopenharmony_ci    default=False,
3321cb0ef41Sopenharmony_ci    action='store_true')
3331cb0ef41Sopenharmony_ci  full_run_g.add_option('--checks',
3341cb0ef41Sopenharmony_ci                        help='Clang-tidy checks to use.',
3351cb0ef41Sopenharmony_ci                        default=None)
3361cb0ef41Sopenharmony_ci  result.add_option_group(full_run_g)
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci  # Aggregate clang-tidy.
3391cb0ef41Sopenharmony_ci  agg_run_g = optparse.OptionGroup(result, 'Clang-tidy aggregate', '')
3401cb0ef41Sopenharmony_ci  agg_run_g.add_option('--aggregate', help='Run clang-tidy on the whole '\
3411cb0ef41Sopenharmony_ci             'codebase and aggregate the warnings',
3421cb0ef41Sopenharmony_ci             default=False, action='store_true')
3431cb0ef41Sopenharmony_ci  agg_run_g.add_option('--show-loc', help='Show file locations when running '\
3441cb0ef41Sopenharmony_ci             'in aggregate mode', default=False,
3451cb0ef41Sopenharmony_ci             action='store_true')
3461cb0ef41Sopenharmony_ci  result.add_option_group(agg_run_g)
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  # Diff clang-tidy.
3491cb0ef41Sopenharmony_ci  diff_run_g = optparse.OptionGroup(result, 'Clang-tidy diff', '')
3501cb0ef41Sopenharmony_ci  diff_run_g.add_option('--branch', help='Run clang-tidy on the diff '\
3511cb0ef41Sopenharmony_ci             'between HEAD and the merge-base between HEAD '\
3521cb0ef41Sopenharmony_ci             'and DIFF_BRANCH (origin/master by default).',
3531cb0ef41Sopenharmony_ci             default=None, dest='diff_branch')
3541cb0ef41Sopenharmony_ci  result.add_option_group(diff_run_g)
3551cb0ef41Sopenharmony_ci
3561cb0ef41Sopenharmony_ci  # Single clang-tidy.
3571cb0ef41Sopenharmony_ci  single_run_g = optparse.OptionGroup(result, 'Clang-tidy single', '')
3581cb0ef41Sopenharmony_ci  single_run_g.add_option(
3591cb0ef41Sopenharmony_ci    '--single', help='', default=False, action='store_true')
3601cb0ef41Sopenharmony_ci  single_run_g.add_option(
3611cb0ef41Sopenharmony_ci    '--file', help='File name to check', default=None, dest='file_name')
3621cb0ef41Sopenharmony_ci  single_run_g.add_option('--lines', help='Limit checks to a line range. '\
3631cb0ef41Sopenharmony_ci              'For example: --lines="[2,4], [5,6]"',
3641cb0ef41Sopenharmony_ci              default=[], dest='line_ranges')
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ci  result.add_option_group(single_run_g)
3671cb0ef41Sopenharmony_ci  return result
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_cidef main():
3711cb0ef41Sopenharmony_ci  parser = GetOptions()
3721cb0ef41Sopenharmony_ci  (options, _) = parser.parse_args()
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  if options.threads is not None:
3751cb0ef41Sopenharmony_ci    global THREADS
3761cb0ef41Sopenharmony_ci    THREADS = options.threads
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci  if options.build_folder is None:
3791cb0ef41Sopenharmony_ci    options.build_folder = DetectBuildFolder()
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  if not CheckClangTidy():
3821cb0ef41Sopenharmony_ci    print('Could not find clang-tidy')
3831cb0ef41Sopenharmony_ci  elif options.build_folder is None or not os.path.isdir(options.build_folder):
3841cb0ef41Sopenharmony_ci    print('Please provide a build folder with -b')
3851cb0ef41Sopenharmony_ci  elif options.gen_compdb:
3861cb0ef41Sopenharmony_ci    GenerateCompileCommands(options.build_folder)
3871cb0ef41Sopenharmony_ci  elif not CheckCompDB(options.build_folder):
3881cb0ef41Sopenharmony_ci    print('Could not find compilation database, ' \
3891cb0ef41Sopenharmony_ci      'please generate it with --gen-compdb')
3901cb0ef41Sopenharmony_ci  else:
3911cb0ef41Sopenharmony_ci    print('Using build folder:', options.build_folder)
3921cb0ef41Sopenharmony_ci    if options.full:
3931cb0ef41Sopenharmony_ci      print('Running clang-tidy - full')
3941cb0ef41Sopenharmony_ci      ClangTidyRunFull(options.build_folder,
3951cb0ef41Sopenharmony_ci                       options.no_output_filter,
3961cb0ef41Sopenharmony_ci                       options.checks,
3971cb0ef41Sopenharmony_ci                       options.auto_fix)
3981cb0ef41Sopenharmony_ci    elif options.aggregate:
3991cb0ef41Sopenharmony_ci      print('Running clang-tidy - aggregating warnings')
4001cb0ef41Sopenharmony_ci      if options.auto_fix:
4011cb0ef41Sopenharmony_ci        print('Auto fix not working in aggregate mode, running without.')
4021cb0ef41Sopenharmony_ci      ClangTidyRunAggregate(options.build_folder, options.show_loc)
4031cb0ef41Sopenharmony_ci    elif options.single:
4041cb0ef41Sopenharmony_ci      print('Running clang-tidy - single on ' + options.file_name)
4051cb0ef41Sopenharmony_ci      if options.file_name is not None:
4061cb0ef41Sopenharmony_ci        line_ranges = []
4071cb0ef41Sopenharmony_ci        for match in re.findall(r'(\[.*?\])', options.line_ranges):
4081cb0ef41Sopenharmony_ci          if match is not []:
4091cb0ef41Sopenharmony_ci            line_ranges.append(match)
4101cb0ef41Sopenharmony_ci        ClangTidyRunSingleFile(options.build_folder,
4111cb0ef41Sopenharmony_ci                               options.file_name,
4121cb0ef41Sopenharmony_ci                               options.auto_fix,
4131cb0ef41Sopenharmony_ci                               line_ranges)
4141cb0ef41Sopenharmony_ci      else:
4151cb0ef41Sopenharmony_ci        print('Filename provided, please specify a filename with --file')
4161cb0ef41Sopenharmony_ci    else:
4171cb0ef41Sopenharmony_ci      print('Running clang-tidy')
4181cb0ef41Sopenharmony_ci      ClangTidyRunDiff(options.build_folder,
4191cb0ef41Sopenharmony_ci                       options.diff_branch,
4201cb0ef41Sopenharmony_ci                       options.auto_fix)
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ciif __name__ == '__main__':
4241cb0ef41Sopenharmony_ci  main()
425