mfherbst updated this revision to Diff 107254.
mfherbst added a comment.

Adapt patch to the changes since the initial submission.

Most notably the introduction of clang-tidy-4.0 changed the format in which 
clang-tidy dumps the required changes. This needs to be taken into account when 
merging the suggested fixes. This patch is now adapted such that it can deal 
with both the old and the new format at the same time.

Please review the patch once again as it differs quite a bit from the initial 
submission.


https://reviews.llvm.org/D31326

Files:
  clang-tidy/tool/run-clang-tidy.py

Index: clang-tidy/tool/run-clang-tidy.py
===================================================================
--- clang-tidy/tool/run-clang-tidy.py
+++ clang-tidy/tool/run-clang-tidy.py
@@ -36,6 +36,7 @@
 
 from __future__ import print_function
 import argparse
+import glob
 import json
 import multiprocessing
 import os
@@ -47,6 +48,7 @@
 import tempfile
 import threading
 import traceback
+import yaml
 
 
 def find_compilation_database(path):
@@ -89,6 +91,38 @@
   return start
 
 
+def merge_replacement_files(tmpdir, mergefile):
+  """Merge all replacement files in a directory into a single file"""
+  # Clang-tidy < 4.0.0 uses "Replacements" as a key to the list
+  # of replacements. Clang-tidy >= 4.0.0 uses "Diagnostics" as the
+  # top-level key.
+  merged={ 'Replacements': [], 'Diagnostics': [], }
+  for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
+    content = yaml.safe_load(open(replacefile, 'r'))
+    if not content:
+      continue # Skip empty files.
+    for k in merged:
+      if content.get(k):
+        merged[k].extend(content[k])
+
+  # Remove empty lists from merged.
+  for k in list(merged.keys()):
+    if not merged[k]:
+      del merged[k]
+
+  if merged:
+    # MainSourceFile: The key is required by the definition inside
+    # include/clang/Tooling/ReplacementsYaml.h, but the value
+    # is actually never used inside clang-apply-replacements,
+    # so we set it to '' here.
+    merged['MainSourceFile'] = ''
+    with open(mergefile, 'w') as out:
+      yaml.safe_dump(merged, out)
+  else:
+    # Empty the file:
+    open(mergefile, 'w').close()
+
+
 def check_clang_apply_replacements_binary(args):
   """Checks if invoking supplied clang-apply-replacements binary works."""
   try:
@@ -101,7 +135,7 @@
 
 
 def apply_fixes(args, tmpdir):
-  """Calls clang-apply-fixes on a given directory. Deletes the dir when done."""
+  """Calls clang-apply-fixes on a given directory."""
   invocation = [args.clang_apply_replacements_binary]
   if args.format:
     invocation.append('-format')
@@ -143,6 +177,9 @@
                       'headers to output diagnostics from. Diagnostics from '
                       'the main file of each translation unit are always '
                       'displayed.')
+  parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+                      help='Create a yaml file to store suggested fixes in, '
+                      'which can be applied with clang-apply-replacements.')
   parser.add_argument('-j', type=int, default=0,
                       help='number of tidy instances to be run in parallel.')
   parser.add_argument('files', nargs='*', default=['.*'],
@@ -194,7 +231,7 @@
     max_task = multiprocessing.cpu_count()
 
   tmpdir = None
-  if args.fix:
+  if args.fix or args.export_fixes:
     check_clang_apply_replacements_binary(args)
     tmpdir = tempfile.mkdtemp()
 
@@ -222,24 +259,32 @@
     # This is a sad hack. Unfortunately subprocess goes
     # bonkers with ctrl-c and we start forking merrily.
     print('\nCtrl-C detected, goodbye.')
-    if args.fix:
+    if tmpdir:
       shutil.rmtree(tmpdir)
     os.kill(0, 9)
 
+  return_code = 0
+  if args.export_fixes:
+    print('Writing fixes to ' + args.export_fixes + ' ...')
+    try:
+      merge_replacement_files(tmpdir, args.export_fixes)
+    except:
+      print('Error exporting fixes.\n', file=sys.stderr)
+      traceback.print_exc()
+      return_code=1
+
   if args.fix:
     print('Applying fixes ...')
-    successfully_applied = False
-
     try:
       apply_fixes(args, tmpdir)
-      successfully_applied = True
     except:
       print('Error applying fixes.\n', file=sys.stderr)
       traceback.print_exc()
+      return_code=1
 
+  if tmpdir:
     shutil.rmtree(tmpdir)
-    if not successfully_applied:
-      sys.exit(1)
+  sys.exit(return_code)
 
 if __name__ == '__main__':
   main()
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to