xref: /aosp_15_r20/external/webrtc/tools_webrtc/clang_tidy.py (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1#!/usr/bin/env vpython3
2
3# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS.  All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10"""Invoke clang-tidy tool.
11
12Usage: clang_tidy.py file.cc [clang-tidy-args...]
13
14Just a proof of concept!
15We use an embedded clang-tidy whose version doesn't match clang++.
16"""
17
18import argparse
19import os
20import shutil
21import subprocess
22import sys
23import tempfile
24from presubmit_checks_lib.build_helpers import (GetClangTidyPath,
25                                                GetCompilationCommand)
26
27# We enable all checkers by default for investigation purpose.
28# This includes clang-analyzer-* checks.
29# Individual checkers can be disabled via command line options.
30# TODO(bugs.webrtc.com/10258): Select checkers relevant to webrtc guidelines.
31CHECKER_OPTION = '-checks=*'
32
33
34def Process(filepath, args):
35  # Build directory is needed to gather compilation flags.
36  # Create a temporary one (instead of reusing an existing one)
37  # to keep the CLI simple and unencumbered.
38  out_dir = tempfile.mkdtemp('clang_tidy')
39
40  try:
41    gn_args = []  # Use default build.
42    command = GetCompilationCommand(filepath, gn_args, out_dir)
43
44    # Remove warning flags. They aren't needed and they cause trouble
45    # when clang-tidy doesn't match most recent clang.
46    # Same battle for -f (e.g. -fcomplete-member-pointers).
47    command = [
48        arg for arg in command
49        if not (arg.startswith('-W') or arg.startswith('-f'))
50    ]
51
52    # Path from build dir.
53    rel_path = os.path.relpath(os.path.abspath(filepath), out_dir)
54
55    # Replace clang++ by clang-tidy
56    command[0:1] = [GetClangTidyPath(), CHECKER_OPTION, rel_path
57                    ] + args + ['--']  # Separator for clang flags.
58    print("Running: %s" % ' '.join(command))
59    # Run from build dir so that relative paths are correct.
60    p = subprocess.Popen(command,
61                         cwd=out_dir,
62                         stdout=sys.stdout,
63                         stderr=sys.stderr)
64    p.communicate()
65    return p.returncode
66  finally:
67    shutil.rmtree(out_dir, ignore_errors=True)
68
69
70def ValidateCC(filepath):
71  """We can only analyze .cc files. Provide explicit message about that."""
72  if filepath.endswith('.cc'):
73    return filepath
74  msg = ('%s not supported.\n'
75         'For now, we can only analyze translation units (.cc files).' %
76         filepath)
77  raise argparse.ArgumentTypeError(msg)
78
79
80def Main():
81  description = (
82      "Run clang-tidy on single cc file.\n"
83      "Use flags, defines and include paths as in default debug build.\n"
84      "WARNING, this is a POC version with rough edges.")
85  parser = argparse.ArgumentParser(description=description)
86  parser.add_argument('filepath',
87                      help='Specifies the path of the .cc file to analyze.',
88                      type=ValidateCC)
89  parser.add_argument('args',
90                      nargs=argparse.REMAINDER,
91                      help='Arguments passed to clang-tidy')
92  parsed_args = parser.parse_args()
93  return Process(parsed_args.filepath, parsed_args.args)
94
95
96if __name__ == '__main__':
97  sys.exit(Main())
98