blob: 49a9427f099eab45739a83512728cfd2766c35c4 [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.
9
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
24#pylint: disable=relative-import
25from presubmit_checks_lib.build_helpers import GetClangTidyPath, \
26 GetCompilationCommand
27
28
29# We enable all checkers by default for investigation purpose.
30# This includes clang-analyzer-* checks.
31# Individual checkers can be disabled via command line options.
32# TODO(bugs.webrtc.com/10258): Select checkers relevant to webrtc guidelines.
33CHECKER_OPTION = '-checks=*'
34
35
36def Process(filepath, args):
37 # Build directory is needed to gather compilation flags.
38 # Create a temporary one (instead of reusing an existing one)
39 # to keep the CLI simple and unencumbered.
40 out_dir = tempfile.mkdtemp('clang_tidy')
41
42 try:
43 gn_args = [] # Use default build.
44 command = GetCompilationCommand(filepath, gn_args, out_dir)
45
46 # Remove warning flags. They aren't needed and they cause trouble
47 # when clang-tidy doesn't match most recent clang.
48 # Same battle for -f (e.g. -fcomplete-member-pointers).
49 command = [arg for arg in command if not (arg.startswith('-W') or
50 arg.startswith('-f'))]
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(),
57 CHECKER_OPTION,
58 rel_path] + args + ['--'] # Separator for clang flags.
59 print "Running: %s" % ' '.join(command)
60 # Run from build dir so that relative paths are correct.
61 p = subprocess.Popen(command, cwd=out_dir,
62 stdout=sys.stdout, stderr=sys.stderr)
63 p.communicate()
64 return p.returncode
65 finally:
66 shutil.rmtree(out_dir, ignore_errors=True)
67
68
69def ValidateCC(filepath):
70 """We can only analyze .cc files. Provide explicit message about that."""
71 if filepath.endswith('.cc'):
72 return filepath
73 msg = ('%s not supported.\n'
74 'For now, we can only analyze translation units (.cc files).' %
75 filepath)
76 raise argparse.ArgumentTypeError(msg)
77
78
79def Main():
80 description = (
81 "Run clang-tidy on single cc file.\n"
82 "Use flags, defines and include paths as in default debug build.\n"
83 "WARNING, this is a POC version with rough edges.")
84 parser = argparse.ArgumentParser(description=description)
85 parser.add_argument('filepath',
86 help='Specifies the path of the .cc file to analyze.',
87 type=ValidateCC)
88 parser.add_argument('args',
89 nargs=argparse.REMAINDER,
90 help='Arguments passed to clang-tidy')
91 parsed_args = parser.parse_args()
92 return Process(parsed_args.filepath, parsed_args.args)
93
94
95if __name__ == '__main__':
96 sys.exit(Main())