blob: bce2549aede0635f797d81f6e44127a54cce91a7 [file] [log] [blame]
Yves Gerey546ee612019-02-26 17:04:16 +01001#!/usr/bin/env python
2# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3#
4# Use of this source code is governed by a BSD-style license
5# that can be found in the LICENSE file in the root of the source
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS. All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
Yves Gerey546ee612019-02-26 17:04:16 +01009"""Invoke clang-tidy tool.
10
11Usage: clang_tidy.py file.cc [clang-tidy-args...]
12
13Just a proof of concept!
14We use an embedded clang-tidy whose version doesn't match clang++.
15"""
16
17import argparse
18import os
19import shutil
20import subprocess
21import sys
22import tempfile
23#pylint: disable=relative-import
24from presubmit_checks_lib.build_helpers import GetClangTidyPath, \
25 GetCompilationCommand
26
Yves Gerey546ee612019-02-26 17:04:16 +010027# 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):
Mirko Bonadei8cc66952020-10-30 10:13:45 +010035 # 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')
Yves Gerey546ee612019-02-26 17:04:16 +010039
Mirko Bonadei8cc66952020-10-30 10:13:45 +010040 try:
41 gn_args = [] # Use default build.
42 command = GetCompilationCommand(filepath, gn_args, out_dir)
Yves Gerey546ee612019-02-26 17:04:16 +010043
Mirko Bonadei8cc66952020-10-30 10:13:45 +010044 # 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 ]
Yves Gerey546ee612019-02-26 17:04:16 +010051
Mirko Bonadei8cc66952020-10-30 10:13:45 +010052 # Path from build dir.
53 rel_path = os.path.relpath(os.path.abspath(filepath), out_dir)
Yves Gerey546ee612019-02-26 17:04:16 +010054
Mirko Bonadei8cc66952020-10-30 10:13:45 +010055 # 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)
Yves Gerey546ee612019-02-26 17:04:16 +010068
69
70def ValidateCC(filepath):
Mirko Bonadei8cc66952020-10-30 10:13:45 +010071 """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)
Yves Gerey546ee612019-02-26 17:04:16 +010078
79
80def Main():
Mirko Bonadei8cc66952020-10-30 10:13:45 +010081 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)
Yves Gerey546ee612019-02-26 17:04:16 +010094
95
96if __name__ == '__main__':
Mirko Bonadei8cc66952020-10-30 10:13:45 +010097 sys.exit(Main())