summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xclang-tools-extra/clang-tidy/tool/run-clang-tidy.py54
1 files changed, 46 insertions, 8 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 d9d827b0129..212cdb82a11 100755
--- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
+++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
@@ -36,6 +36,7 @@ http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
from __future__ import print_function
import argparse
+import glob
import json
import multiprocessing
import os
@@ -47,6 +48,7 @@ import sys
import tempfile
import threading
import traceback
+import yaml
def find_compilation_database(path):
@@ -89,6 +91,31 @@ def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
return start
+def merge_replacement_files(tmpdir, mergefile):
+ """Merge all replacement files in a directory into a single file"""
+ # The fixes suggested by clang-tidy >= 4.0.0 are given under
+ # the top level key 'Diagnostics' in the output yaml files
+ mergekey="Diagnostics"
+ merged=[]
+ for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
+ content = yaml.safe_load(open(replacefile, 'r'))
+ if not content:
+ continue # Skip empty files.
+ merged.extend(content.get(mergekey, []))
+
+ 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.
+ output = { 'MainSourceFile': '', mergekey: merged }
+ with open(mergefile, 'w') as out:
+ yaml.safe_dump(output, 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 +128,7 @@ def check_clang_apply_replacements_binary(args):
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 +170,9 @@ def main():
'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 +224,7 @@ def main():
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 +252,32 @@ 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 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()
OpenPOWER on IntegriCloud