Index: run-clang-tidy.py =================================================================== --- run-clang-tidy.py +++ run-clang-tidy.py @@ -35,6 +35,7 @@ """ import argparse +import glob import json import multiprocessing import os @@ -45,6 +46,7 @@ import sys import tempfile import threading +import yaml def find_compilation_database(path): @@ -87,14 +89,36 @@ return start +def merge_replacement_files(tmpdir, fixfile): + """Merge all replacement files in a directory into a single fixfile""" + # MainSourceFile: The key is required by the definition inside + # include/clang/Tooling/ReplacementsYaml.h, but the value + # is actually never usid inside clang-apply-replacements, + # so we set it to '' here. + merged={ 'MainSourceFile': '', 'Replacements': [] } + + for replacefile in glob.iglob(tmpdir + '/*.yaml'): + with open(replacefile, 'r') as f: + content = yaml.safe_load(f) + if not content: + continue # Skip empty files + + try: + merged['Replacements'].extend(content['Replacements']) + except KeyError: + pass # Ignore files with missing keys + + if merged['Replacements']: + with open(fixfile,'w') as out: + yaml.safe_dump(merged, out) + 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') invocation.append(tmpdir) subprocess.call(invocation) - shutil.rmtree(tmpdir) def run_tidy(args, tmpdir, build_path, queue): @@ -129,6 +153,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=['.*'], @@ -178,7 +205,7 @@ max_task = multiprocessing.cpu_count() tmpdir = None - if args.fix: + if args.fix or args.export_fixes: tmpdir = tempfile.mkdtemp() # Build up a big regexy filter from all command line arguments. @@ -205,13 +232,20 @@ # 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) + if args.export_fixes: + print 'Writing fixes to ' + args.export_fixes + merge_replacement_files(tmpdir, args.export_fixes) + if args.fix: print 'Applying fixes ...' apply_fixes(args, tmpdir) + if tmpdir: + shutil.rmtree(tmpdir) + if __name__ == '__main__': main()