Skip to content

Commit

Permalink
[run-clang-tidy,clang-tidy-diff] Accept directory as value for -expor…
Browse files Browse the repository at this point in the history
…t-fixes (#69453)

Adding an additional parameter to run_clang_tidy.py to accept a
directory where the clang-tidy fixes are saved to. This directory can
then be used to run `clang-apply-replacements`.

Closes #69450
  • Loading branch information
amgebauer committed Oct 20, 2023
1 parent 6e3572c commit 5557d98
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 27 deletions.
42 changes: 30 additions & 12 deletions clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,12 @@ def main():
if yaml:
parser.add_argument(
"-export-fixes",
metavar="FILE",
metavar="FILE_OR_DIRECTORY",
dest="export_fixes",
help="Create a yaml file to store suggested fixes in, "
"which can be applied with clang-apply-replacements.",
help="A directory or a yaml file to store suggested fixes in, "
"which can be applied with clang-apply-replacements. If the "
"parameter is a directory, the fixes of each compilation unit are "
"stored in individual yaml files in the directory.",
)
parser.add_argument(
"-extra-arg",
Expand Down Expand Up @@ -258,9 +260,25 @@ def main():
max_task_count = multiprocessing.cpu_count()
max_task_count = min(len(lines_by_file), max_task_count)

tmpdir = None
if yaml and args.export_fixes:
tmpdir = tempfile.mkdtemp()
combine_fixes = False
export_fixes_dir = None
delete_fixes_dir = False
if args.export_fixes is not None:
# if a directory is given, create it if it does not exist
if args.export_fixes.endswith(os.path.sep) and not os.path.isdir(
args.export_fixes
):
os.makedirs(args.export_fixes)

if not os.path.isdir(args.export_fixes) and yaml:
combine_fixes = True

if os.path.isdir(args.export_fixes):
export_fixes_dir = args.export_fixes

if combine_fixes:
export_fixes_dir = tempfile.mkdtemp()
delete_fixes_dir = True

# Tasks for clang-tidy.
task_queue = queue.Queue(max_task_count)
Expand Down Expand Up @@ -302,10 +320,10 @@ def main():
# Run clang-tidy on files containing changes.
command = [args.clang_tidy_binary]
command.append("-line-filter=" + line_filter_json)
if yaml and args.export_fixes:
if args.export_fixes is not None:
# Get a temporary file. We immediately close the handle so clang-tidy can
# overwrite it.
(handle, tmp_name) = tempfile.mkstemp(suffix=".yaml", dir=tmpdir)
(handle, tmp_name) = tempfile.mkstemp(suffix=".yaml", dir=export_fixes_dir)
os.close(handle)
command.append("-export-fixes=" + tmp_name)
command.extend(common_clang_tidy_args)
Expand All @@ -324,17 +342,17 @@ def main():
if failed_files:
return_code = 1

if yaml and args.export_fixes:
if combine_fixes:
print("Writing fixes to " + args.export_fixes + " ...")
try:
merge_replacement_files(tmpdir, args.export_fixes)
merge_replacement_files(export_fixes_dir, args.export_fixes)
except:
sys.stderr.write("Error exporting fixes.\n")
traceback.print_exc()
return_code = 1

if tmpdir:
shutil.rmtree(tmpdir)
if delete_fixes_dir:
shutil.rmtree(export_fixes_dir)
sys.exit(return_code)


Expand Down
46 changes: 32 additions & 14 deletions clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,12 @@ def main():
if yaml:
parser.add_argument(
"-export-fixes",
metavar="filename",
metavar="file_or_directory",
dest="export_fixes",
help="Create a yaml file to store suggested fixes in, "
"which can be applied with clang-apply-replacements.",
help="A directory or a yaml file to store suggested fixes in, "
"which can be applied with clang-apply-replacements. If the "
"parameter is a directory, the fixes of each compilation unit are "
"stored in individual yaml files in the directory.",
)
parser.add_argument(
"-j",
Expand Down Expand Up @@ -384,14 +386,30 @@ def main():

clang_tidy_binary = find_binary(args.clang_tidy_binary, "clang-tidy", build_path)

tmpdir = None
if args.fix:
clang_apply_replacements_binary = find_binary(
args.clang_apply_replacements_binary, "clang-apply-replacements", build_path
)

if args.fix or (yaml and args.export_fixes):
tmpdir = tempfile.mkdtemp()
combine_fixes = False
export_fixes_dir = None
delete_fixes_dir = False
if args.export_fixes is not None:
# if a directory is given, create it if it does not exist
if args.export_fixes.endswith(os.path.sep) and not os.path.isdir(
args.export_fixes
):
os.makedirs(args.export_fixes)

if not os.path.isdir(args.export_fixes) and yaml:
combine_fixes = True

if os.path.isdir(args.export_fixes):
export_fixes_dir = args.export_fixes

if export_fixes_dir is None and (args.fix or combine_fixes):
export_fixes_dir = tempfile.mkdtemp()
delete_fixes_dir = True

try:
invocation = get_tidy_invocation(
Expand Down Expand Up @@ -450,7 +468,7 @@ def main():
args=(
args,
clang_tidy_binary,
tmpdir,
export_fixes_dir,
build_path,
task_queue,
lock,
Expand All @@ -474,14 +492,14 @@ def main():
# This is a sad hack. Unfortunately subprocess goes
# bonkers with ctrl-c and we start forking merrily.
print("\nCtrl-C detected, goodbye.")
if tmpdir:
shutil.rmtree(tmpdir)
if delete_fixes_dir:
shutil.rmtree(export_fixes_dir)
os.kill(0, 9)

if yaml and args.export_fixes:
if combine_fixes:
print("Writing fixes to " + args.export_fixes + " ...")
try:
merge_replacement_files(tmpdir, args.export_fixes)
merge_replacement_files(export_fixes_dir, args.export_fixes)
except:
print("Error exporting fixes.\n", file=sys.stderr)
traceback.print_exc()
Expand All @@ -490,14 +508,14 @@ def main():
if args.fix:
print("Applying fixes ...")
try:
apply_fixes(args, clang_apply_replacements_binary, tmpdir)
apply_fixes(args, clang_apply_replacements_binary, export_fixes_dir)
except:
print("Error applying fixes.\n", file=sys.stderr)
traceback.print_exc()
return_code = 1

if tmpdir:
shutil.rmtree(tmpdir)
if delete_fixes_dir:
shutil.rmtree(export_fixes_dir)
sys.exit(return_code)


Expand Down
7 changes: 6 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ Improvements to clang-tidy

- Improved :program:`clang-tidy-diff.py` script. It now returns exit code `1`
if any :program:`clang-tidy` subprocess exits with a non-zero code or if
exporting fixes fails.
exporting fixes fails. It now accepts a directory as a value for
`-export-fixes` to export individual yaml files for each compilation unit.

- Improved :program:`run-clang-tidy.py` script. It now accepts a directory
as a value for `-export-fixes` to export individual yaml files for each
compilation unit.

New checks
^^^^^^^^^^
Expand Down

0 comments on commit 5557d98

Please sign in to comment.