blob: b3f738eab3712f782322427e0208e62982985ba4 [file] [log] [blame]
#!/usr/bin/env vpython3
# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
"""Invoke clang-tidy tool.
Usage: clang_tidy.py file.cc [clang-tidy-args...]
Just a proof of concept!
We use an embedded clang-tidy whose version doesn't match clang++.
"""
import argparse
import os
import shutil
import subprocess
import sys
import tempfile
from presubmit_checks_lib.build_helpers import (GetClangTidyPath,
GetCompilationCommand)
# We enable all checkers by default for investigation purpose.
# This includes clang-analyzer-* checks.
# Individual checkers can be disabled via command line options.
# TODO(bugs.webrtc.com/10258): Select checkers relevant to webrtc guidelines.
CHECKER_OPTION = '-checks=*'
def Process(filepath, args):
# Build directory is needed to gather compilation flags.
# Create a temporary one (instead of reusing an existing one)
# to keep the CLI simple and unencumbered.
out_dir = tempfile.mkdtemp('clang_tidy')
try:
gn_args = [] # Use default build.
command = GetCompilationCommand(filepath, gn_args, out_dir)
# Remove warning flags. They aren't needed and they cause trouble
# when clang-tidy doesn't match most recent clang.
# Same battle for -f (e.g. -fcomplete-member-pointers).
command = [
arg for arg in command
if not (arg.startswith('-W') or arg.startswith('-f'))
]
# Path from build dir.
rel_path = os.path.relpath(os.path.abspath(filepath), out_dir)
# Replace clang++ by clang-tidy
command[0:1] = [GetClangTidyPath(), CHECKER_OPTION, rel_path
] + args + ['--'] # Separator for clang flags.
print("Running: %s" % ' '.join(command))
# Run from build dir so that relative paths are correct.
p = subprocess.Popen(command,
cwd=out_dir,
stdout=sys.stdout,
stderr=sys.stderr)
p.communicate()
return p.returncode
finally:
shutil.rmtree(out_dir, ignore_errors=True)
def ValidateCC(filepath):
"""We can only analyze .cc files. Provide explicit message about that."""
if filepath.endswith('.cc'):
return filepath
msg = ('%s not supported.\n'
'For now, we can only analyze translation units (.cc files).' %
filepath)
raise argparse.ArgumentTypeError(msg)
def Main():
description = (
"Run clang-tidy on single cc file.\n"
"Use flags, defines and include paths as in default debug build.\n"
"WARNING, this is a POC version with rough edges.")
parser = argparse.ArgumentParser(description=description)
parser.add_argument('filepath',
help='Specifies the path of the .cc file to analyze.',
type=ValidateCC)
parser.add_argument('args',
nargs=argparse.REMAINDER,
help='Arguments passed to clang-tidy')
parsed_args = parser.parse_args()
return Process(parsed_args.filepath, parsed_args.args)
if __name__ == '__main__':
sys.exit(Main())