diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # #===- run-clang-tidy.py - Parallel clang-tidy runner --------*- python -*--===# # @@ -41,6 +41,7 @@ import json import multiprocessing import os +import queue import re import shutil import subprocess @@ -54,13 +55,6 @@ except ImportError: yaml = None -is_py2 = sys.version[0] == '2' - -if is_py2: - import Queue as queue -else: - import queue as queue - def strtobool(val): """Convert a string representation of truth to a bool following LLVM's CLI argument parsing.""" @@ -158,20 +152,29 @@ open(mergefile, 'w').close() -def check_clang_apply_replacements_binary(args): - """Checks if invoking supplied clang-apply-replacements binary works.""" - try: - subprocess.check_call([args.clang_apply_replacements_binary, '--version']) - except: - print('Unable to run clang-apply-replacements. Is clang-apply-replacements ' - 'binary correctly specified?', file=sys.stderr) - traceback.print_exc() - sys.exit(1) +def find_binary(arg, name, build_path): + """Get the path for a binary or exit""" + if arg: + if shutil.which(arg): + return arg + else: + raise SystemExit( + "error: passed binary '{}' was not found or is not executable" + .format(arg)) + built_path = os.path.join(build_path, "bin", name) + binary = shutil.which(name) or shutil.which(built_path) + if binary: + return binary + else: + raise SystemExit( + "error: failed to find {} in $PATH or at {}" + .format(name, built_path)) -def apply_fixes(args, tmpdir): + +def apply_fixes(args, clang_apply_replacements_binary, tmpdir): """Calls clang-apply-fixes on a given directory.""" - invocation = [args.clang_apply_replacements_binary] + invocation = [clang_apply_replacements_binary] if args.format: invocation.append('-format') if args.style: @@ -180,11 +183,12 @@ subprocess.call(invocation) -def run_tidy(args, tmpdir, build_path, queue, lock, failed_files): +def run_tidy(args, clang_tidy_binary, tmpdir, build_path, queue, lock, + failed_files): """Takes filenames out of queue and runs clang-tidy on them.""" while True: name = queue.get() - invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks, + invocation = get_tidy_invocation(name, clang_tidy_binary, args.checks, tmpdir, build_path, args.header_filter, args.allow_enabling_alpha_checkers, args.extra_arg, args.extra_arg_before, @@ -210,15 +214,13 @@ parser = argparse.ArgumentParser(description='Runs clang-tidy over all files ' 'in a compilation database. Requires ' 'clang-tidy and clang-apply-replacements in ' - '$PATH.') + '$PATH or in your build directory.') parser.add_argument('-allow-enabling-alpha-checkers', action='store_true', help='allow alpha checkers from ' 'clang-analyzer.') parser.add_argument('-clang-tidy-binary', metavar='PATH', - default='clang-tidy', help='path to clang-tidy binary') parser.add_argument('-clang-apply-replacements-binary', metavar='PATH', - default='clang-apply-replacements', help='path to clang-apply-replacements binary') parser.add_argument('-checks', default=None, help='checks filter, when not specified, use clang-tidy ' @@ -278,8 +280,18 @@ # Find our database build_path = find_compilation_database(db_path) + clang_tidy_binary = find_binary(args.clang_tidy_binary, "clang-tidy", + build_path) + + tmpdir = None + if args.fix or (yaml and args.export_fixes): + clang_apply_replacements_binary = find_binary( + args.clang_apply_replacements_binary, "clang-apply-replacements", + build_path) + tmpdir = tempfile.mkdtemp() + try: - invocation = get_tidy_invocation("", args.clang_tidy_binary, args.checks, + invocation = get_tidy_invocation("", clang_tidy_binary, args.checks, None, build_path, args.header_filter, args.allow_enabling_alpha_checkers, args.extra_arg, args.extra_arg_before, @@ -306,11 +318,6 @@ if max_task == 0: max_task = multiprocessing.cpu_count() - tmpdir = None - if args.fix or (yaml and args.export_fixes): - check_clang_apply_replacements_binary(args) - tmpdir = tempfile.mkdtemp() - # Build up a big regexy filter from all command line arguments. file_name_re = re.compile('|'.join(args.files)) @@ -323,7 +330,8 @@ lock = threading.Lock() for _ in range(max_task): t = threading.Thread(target=run_tidy, - args=(args, tmpdir, build_path, task_queue, lock, failed_files)) + args=(args, clang_tidy_binary, tmpdir, build_path, + task_queue, lock, failed_files)) t.daemon = True t.start() @@ -357,7 +365,7 @@ if args.fix: print('Applying fixes ...') try: - apply_fixes(args, tmpdir) + apply_fixes(args, clang_apply_replacements_binary, tmpdir) except: print('Error applying fixes.\n', file=sys.stderr) traceback.print_exc()