[clang-tools-extra] r217368 - [clang-tidy] Add a little python script that can run clang-tidy and apply fixes over an entire codebase.
Benjamin Kramer
benny.kra at googlemail.com
Mon Sep 8 07:01:31 PDT 2014
Author: d0k
Date: Mon Sep 8 09:01:31 2014
New Revision: 217368
URL: http://llvm.org/viewvc/llvm-project?rev=217368&view=rev
Log:
[clang-tidy] Add a little python script that can run clang-tidy and apply fixes over an entire codebase.
Ever wanted to fix all the header guards in clang? Now it's easy.
Make sure clang-tidy is in $PATH and a compilation database is available.
$ ./run-clang-tidy.py -checks=-*,llvm-header-guard -fix
... get coffee (or more CPU cores) ...
$ svn diff
Some may argue that this is just a glorified xargs -P, but it does a bit more ;)
Differential Revision: http://reviews.llvm.org/D5188
Added:
clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py (with props)
Added: clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py?rev=217368&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py (added)
+++ clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py Mon Sep 8 09:01:31 2014
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+#
+#===- run-clang-tidy.py - Parallel clang-tidy runner ---------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+# FIXME: Integrate with clang-tidy-diff.py
+
+"""
+Parallel clang-tidy runner
+==========================
+
+Runs clang-tidy over all files in a compilation database. Requires clang-tidy
+and clang-apply-replacements in $PATH.
+
+Example invocations.
+- Run clang-tidy on all files in the current working directory with a default
+ set of checks and show warnings in the cpp files and all project headers.
+ run-clang-tidy.py $PWD
+
+- Fix all header guards.
+ run-clang-tidy.py -fix -checks=-*,llvm-header-guard
+
+- Fix all header guards included from clang-tidy and header guards
+ for clang-tidy headers.
+ run-clang-tidy.py -fix -checks=-*,llvm-header-guard extra/clang-tidy \
+ -header-filter=extra/clang-tidy
+
+Compilation database setup:
+http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+"""
+
+import argparse
+import json
+import multiprocessing
+import os
+import Queue
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+
+
+def find_compilation_database(path):
+ """Adjusts the directory until a compilation database is found."""
+ result = './'
+ while not os.path.isfile(os.path.join(result, path)):
+ if os.path.realpath(result) == '/':
+ print 'Error: could not find compilation database.'
+ sys.exit(1)
+ result += '../'
+ return os.path.realpath(result)
+
+
+def get_tidy_invocation(f, checks, tmpdir, build_path, header_filter):
+ """Gets a command line for clang-tidy."""
+ start = ['clang-tidy']
+ if header_filter is not None:
+ start.append('-header-filter=' + header_filter)
+ else:
+ # Show warnings in all in-project headers by default.
+ start.append('-header-filter=^' + build_path + '/.*')
+ if checks:
+ start.append('-checks=-*,' + checks)
+ if tmpdir is not None:
+ start.append('-export-fixes')
+ # Get a temporary file. We immediately close the handle so clang-tidy can
+ # overwrite it.
+ (handle, name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
+ handle.close()
+ start.append(name)
+ start.append('-p=' + build_path)
+ start.append(f)
+ return start
+
+
+def apply_fixes(tmpdir, format_enabled):
+ """Calls clang-apply-fixes on a given directory. Deletes the dir when done."""
+ invocation = ['clang-apply-replacements']
+ if format_enabled:
+ invocation.append('-format')
+ invocation.append(tmpdir)
+ subprocess.call(invocation)
+ shutil.rmtree(tmpdir)
+
+
+def run_tidy(args, tmpdir, build_path, queue):
+ """Takes filenames out of queue and runs clang-tidy on them."""
+ while True:
+ name = queue.get()
+ invocation = get_tidy_invocation(name, args.checks, tmpdir,
+ build_path, args.header_filter)
+ sys.stdout.write(' '.join(invocation) + '\n')
+ subprocess.call(invocation)
+ queue.task_done()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Runs clang-tidy over all files '
+ 'in a compilation database. Requires '
+ 'clang-tidy and clang-apply-replacements in '
+ '$PATH.')
+ parser.add_argument('-checks', default=None,
+ help='checks filter, when not specified, use clang-tidy '
+ 'default')
+ parser.add_argument('-header-filter', default=None,
+ help='regular expression matching the names of the '
+ 'headers to output diagnostics from. Diagnostics from '
+ 'the main file of each translation unit are always '
+ 'displayed.')
+ parser.add_argument('-j', type=int, default=0,
+ help='number of tidy instances to be run in parallel.')
+ parser.add_argument('files', nargs='*', default=['.*'],
+ help='files to be processed (regex on path)')
+ parser.add_argument('-fix', action='store_true', help='apply fix-its')
+ parser.add_argument('-format', action='store_true', help='Reformat code '
+ 'after applying fixes')
+ args = parser.parse_args()
+
+ # Find our database.
+ db_path = 'compile_commands.json'
+ build_path = find_compilation_database(db_path)
+
+ # Load the database and extract all files.
+ database = json.load(open(os.path.join(build_path, db_path)))
+ files = [entry['file'] for entry in database]
+
+ max_task = args.j
+ if max_task == 0:
+ max_task = multiprocessing.cpu_count()
+
+ tmpdir = None
+ if args.fix:
+ tmpdir = tempfile.mkdtemp()
+
+ # Build up a big regexy filter from all command line arguments.
+ file_name_re = re.compile('(' + ')|('.join(args.files) + ')')
+
+ try:
+ # Spin up a bunch of tidy-launching threads.
+ queue = Queue.Queue(max_task)
+ for _ in range(max_task):
+ t = threading.Thread(target=run_tidy,
+ args=(args, tmpdir, build_path, queue))
+ t.daemon = True
+ t.start()
+
+ # Fill the queue with files.
+ for name in files:
+ if file_name_re.search(name):
+ queue.put(name)
+
+ # Wait for all threads to be done.
+ queue.join()
+
+ except KeyboardInterrupt:
+ # 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:
+ shutil.rmtree(tmpdir)
+ os.kill(0, 9)
+
+ if args.fix:
+ print 'Applying fixes ...'
+ apply_fixes(tmpdir, args.format)
+
+if __name__ == '__main__':
+ main()
Propchange: clang-tools-extra/trunk/clang-tidy/tool/run-clang-tidy.py
------------------------------------------------------------------------------
svn:executable = *
More information about the cfe-commits
mailing list