Skip to content

Commit 5557d98

Browse files
authored
[run-clang-tidy,clang-tidy-diff] Accept directory as value for -export-fixes (llvm#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 llvm#69450
1 parent 6e3572c commit 5557d98

File tree

3 files changed

+68
-27
lines changed

3 files changed

+68
-27
lines changed

clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,12 @@ def main():
180180
if yaml:
181181
parser.add_argument(
182182
"-export-fixes",
183-
metavar="FILE",
183+
metavar="FILE_OR_DIRECTORY",
184184
dest="export_fixes",
185-
help="Create a yaml file to store suggested fixes in, "
186-
"which can be applied with clang-apply-replacements.",
185+
help="A directory or a yaml file to store suggested fixes in, "
186+
"which can be applied with clang-apply-replacements. If the "
187+
"parameter is a directory, the fixes of each compilation unit are "
188+
"stored in individual yaml files in the directory.",
187189
)
188190
parser.add_argument(
189191
"-extra-arg",
@@ -258,9 +260,25 @@ def main():
258260
max_task_count = multiprocessing.cpu_count()
259261
max_task_count = min(len(lines_by_file), max_task_count)
260262

261-
tmpdir = None
262-
if yaml and args.export_fixes:
263-
tmpdir = tempfile.mkdtemp()
263+
combine_fixes = False
264+
export_fixes_dir = None
265+
delete_fixes_dir = False
266+
if args.export_fixes is not None:
267+
# if a directory is given, create it if it does not exist
268+
if args.export_fixes.endswith(os.path.sep) and not os.path.isdir(
269+
args.export_fixes
270+
):
271+
os.makedirs(args.export_fixes)
272+
273+
if not os.path.isdir(args.export_fixes) and yaml:
274+
combine_fixes = True
275+
276+
if os.path.isdir(args.export_fixes):
277+
export_fixes_dir = args.export_fixes
278+
279+
if combine_fixes:
280+
export_fixes_dir = tempfile.mkdtemp()
281+
delete_fixes_dir = True
264282

265283
# Tasks for clang-tidy.
266284
task_queue = queue.Queue(max_task_count)
@@ -302,10 +320,10 @@ def main():
302320
# Run clang-tidy on files containing changes.
303321
command = [args.clang_tidy_binary]
304322
command.append("-line-filter=" + line_filter_json)
305-
if yaml and args.export_fixes:
323+
if args.export_fixes is not None:
306324
# Get a temporary file. We immediately close the handle so clang-tidy can
307325
# overwrite it.
308-
(handle, tmp_name) = tempfile.mkstemp(suffix=".yaml", dir=tmpdir)
326+
(handle, tmp_name) = tempfile.mkstemp(suffix=".yaml", dir=export_fixes_dir)
309327
os.close(handle)
310328
command.append("-export-fixes=" + tmp_name)
311329
command.extend(common_clang_tidy_args)
@@ -324,17 +342,17 @@ def main():
324342
if failed_files:
325343
return_code = 1
326344

327-
if yaml and args.export_fixes:
345+
if combine_fixes:
328346
print("Writing fixes to " + args.export_fixes + " ...")
329347
try:
330-
merge_replacement_files(tmpdir, args.export_fixes)
348+
merge_replacement_files(export_fixes_dir, args.export_fixes)
331349
except:
332350
sys.stderr.write("Error exporting fixes.\n")
333351
traceback.print_exc()
334352
return_code = 1
335353

336-
if tmpdir:
337-
shutil.rmtree(tmpdir)
354+
if delete_fixes_dir:
355+
shutil.rmtree(export_fixes_dir)
338356
sys.exit(return_code)
339357

340358

clang-tools-extra/clang-tidy/tool/run-clang-tidy.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,12 @@ def main():
308308
if yaml:
309309
parser.add_argument(
310310
"-export-fixes",
311-
metavar="filename",
311+
metavar="file_or_directory",
312312
dest="export_fixes",
313-
help="Create a yaml file to store suggested fixes in, "
314-
"which can be applied with clang-apply-replacements.",
313+
help="A directory or a yaml file to store suggested fixes in, "
314+
"which can be applied with clang-apply-replacements. If the "
315+
"parameter is a directory, the fixes of each compilation unit are "
316+
"stored in individual yaml files in the directory.",
315317
)
316318
parser.add_argument(
317319
"-j",
@@ -384,14 +386,30 @@ def main():
384386

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

387-
tmpdir = None
388389
if args.fix:
389390
clang_apply_replacements_binary = find_binary(
390391
args.clang_apply_replacements_binary, "clang-apply-replacements", build_path
391392
)
392393

393-
if args.fix or (yaml and args.export_fixes):
394-
tmpdir = tempfile.mkdtemp()
394+
combine_fixes = False
395+
export_fixes_dir = None
396+
delete_fixes_dir = False
397+
if args.export_fixes is not None:
398+
# if a directory is given, create it if it does not exist
399+
if args.export_fixes.endswith(os.path.sep) and not os.path.isdir(
400+
args.export_fixes
401+
):
402+
os.makedirs(args.export_fixes)
403+
404+
if not os.path.isdir(args.export_fixes) and yaml:
405+
combine_fixes = True
406+
407+
if os.path.isdir(args.export_fixes):
408+
export_fixes_dir = args.export_fixes
409+
410+
if export_fixes_dir is None and (args.fix or combine_fixes):
411+
export_fixes_dir = tempfile.mkdtemp()
412+
delete_fixes_dir = True
395413

396414
try:
397415
invocation = get_tidy_invocation(
@@ -450,7 +468,7 @@ def main():
450468
args=(
451469
args,
452470
clang_tidy_binary,
453-
tmpdir,
471+
export_fixes_dir,
454472
build_path,
455473
task_queue,
456474
lock,
@@ -474,14 +492,14 @@ def main():
474492
# This is a sad hack. Unfortunately subprocess goes
475493
# bonkers with ctrl-c and we start forking merrily.
476494
print("\nCtrl-C detected, goodbye.")
477-
if tmpdir:
478-
shutil.rmtree(tmpdir)
495+
if delete_fixes_dir:
496+
shutil.rmtree(export_fixes_dir)
479497
os.kill(0, 9)
480498

481-
if yaml and args.export_fixes:
499+
if combine_fixes:
482500
print("Writing fixes to " + args.export_fixes + " ...")
483501
try:
484-
merge_replacement_files(tmpdir, args.export_fixes)
502+
merge_replacement_files(export_fixes_dir, args.export_fixes)
485503
except:
486504
print("Error exporting fixes.\n", file=sys.stderr)
487505
traceback.print_exc()
@@ -490,14 +508,14 @@ def main():
490508
if args.fix:
491509
print("Applying fixes ...")
492510
try:
493-
apply_fixes(args, clang_apply_replacements_binary, tmpdir)
511+
apply_fixes(args, clang_apply_replacements_binary, export_fixes_dir)
494512
except:
495513
print("Error applying fixes.\n", file=sys.stderr)
496514
traceback.print_exc()
497515
return_code = 1
498516

499-
if tmpdir:
500-
shutil.rmtree(tmpdir)
517+
if delete_fixes_dir:
518+
shutil.rmtree(export_fixes_dir)
501519
sys.exit(return_code)
502520

503521

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ Improvements to clang-tidy
120120

121121
- Improved :program:`clang-tidy-diff.py` script. It now returns exit code `1`
122122
if any :program:`clang-tidy` subprocess exits with a non-zero code or if
123-
exporting fixes fails.
123+
exporting fixes fails. It now accepts a directory as a value for
124+
`-export-fixes` to export individual yaml files for each compilation unit.
125+
126+
- Improved :program:`run-clang-tidy.py` script. It now accepts a directory
127+
as a value for `-export-fixes` to export individual yaml files for each
128+
compilation unit.
124129

125130
New checks
126131
^^^^^^^^^^

0 commit comments

Comments
 (0)