[clang-tools-extra] [run-clang-tidy, clang-tidy-diff] Accept directory as value for -export-fixes (PR #69453)

Amadeus Gebauer via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 18 08:50:44 PDT 2023


https://github.com/amgebauer updated https://github.com/llvm/llvm-project/pull/69453

>From 182198f8ca07e458fa34158fcdbfa72310ff12f4 Mon Sep 17 00:00:00 2001
From: Amadeus Gebauer <amadeus.gebauer at tum.de>
Date: Wed, 18 Oct 2023 14:02:44 +0200
Subject: [PATCH 1/2] [run-clang-tidy] Accept directory for -export-fixes

---
 .../clang-tidy/tool/run-clang-tidy.py         | 46 +++++++++++++------
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 ++
 2 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
index 312d9241cfa57c5..aa628aa87800693 100755
--- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
+++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
@@ -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",
@@ -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(
@@ -450,7 +468,7 @@ def main():
                 args=(
                     args,
                     clang_tidy_binary,
-                    tmpdir,
+                    export_fixes_dir,
                     build_path,
                     task_queue,
                     lock,
@@ -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()
@@ -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)
 
 
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3e1fbe091c9ff6a..fd9f25953ae4929 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -122,6 +122,10 @@ Improvements to clang-tidy
   if any :program:`clang-tidy` subprocess exits with a non-zero code or if
   exporting fixes fails.
 
+- 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
 ^^^^^^^^^^
 

>From 9544ce91dfeecc7af88e39de4cb8a31691474bac Mon Sep 17 00:00:00 2001
From: Amadeus Gebauer <amadeus.gebauer at tum.de>
Date: Wed, 18 Oct 2023 16:52:13 +0200
Subject: [PATCH 2/2] [clang-tidy-diff] Accept directory for -export-fixes

---
 .../clang-tidy/tool/clang-tidy-diff.py        | 40 ++++++++++++++-----
 clang-tools-extra/docs/ReleaseNotes.rst       |  3 +-
 2 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
index 06f2cebe7c09e60..cb8e0768d0df953 100755
--- a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
+++ b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
@@ -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",
@@ -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)
@@ -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 combine_fixes:
             # 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)
@@ -327,14 +345,14 @@ def main():
     if yaml and args.export_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)
 
 
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index fd9f25953ae4929..366b3abbe1244bf 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -120,7 +120,8 @@ 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



More information about the cfe-commits mailing list