14 Parallel clang-tidy runner
15 ==========================
17 Runs clang-tidy over all files in a compilation database. Requires clang-tidy
18 and clang-apply-replacements in $PATH.
21 - Run clang-tidy on all files in the current working directory with a default
22 set of checks and show warnings in the cpp files and all project headers.
23 run-clang-tidy.py $PWD
25 - Fix all header guards.
26 run-clang-tidy.py -fix -checks=-*,llvm-header-guard
28 - Fix all header guards included from clang-tidy and header guards
29 for clang-tidy headers.
30 run-clang-tidy.py -fix -checks=-*,llvm-header-guard extra/clang-tidy \
31 -header-filter=extra/clang-tidy
33 Compilation database setup:
34 http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
37 from __future__
import print_function
40 import multiprocessing
53 """Adjusts the directory until a compilation database is found."""
55 while not os.path.isfile(os.path.join(result, path)):
56 if os.path.realpath(result) ==
'/':
57 print(
'Error: could not find compilation database.')
60 return os.path.realpath(result)
64 header_filter, extra_arg, extra_arg_before, quiet):
65 """Gets a command line for clang-tidy."""
66 start = [clang_tidy_binary]
67 if header_filter
is not None:
68 start.append(
'-header-filter=' + header_filter)
71 start.append(
'-header-filter=^' + build_path +
'/.*')
73 start.append(
'-checks=' + checks)
74 if tmpdir
is not None:
75 start.append(
'-export-fixes')
78 (handle, name) = tempfile.mkstemp(suffix=
'.yaml', dir=tmpdir)
82 start.append(
'-extra-arg=%s' % arg)
83 for arg
in extra_arg_before:
84 start.append(
'-extra-arg-before=%s' % arg)
85 start.append(
'-p=' + build_path)
87 start.append(
'-quiet')
93 """Checks if invoking supplied clang-apply-replacements binary works."""
95 subprocess.check_call([args.clang_apply_replacements_binary,
'--version'])
97 print(
'Unable to run clang-apply-replacements. Is clang-apply-replacements '
98 'binary correctly specified?', file=sys.stderr)
104 """Calls clang-apply-fixes on a given directory. Deletes the dir when done."""
105 invocation = [args.clang_apply_replacements_binary]
107 invocation.append(
'-format')
109 invocation.append(
'-style=' + args.style)
110 invocation.append(tmpdir)
111 subprocess.call(invocation)
115 """Takes filenames out of queue and runs clang-tidy on them."""
119 tmpdir, build_path, args.header_filter,
120 args.extra_arg, args.extra_arg_before,
122 sys.stdout.write(
' '.
join(invocation) +
'\n')
123 subprocess.call(invocation)
128 parser = argparse.ArgumentParser(description=
'Runs clang-tidy over all files '
129 'in a compilation database. Requires '
130 'clang-tidy and clang-apply-replacements in '
132 parser.add_argument(
'-clang-tidy-binary', metavar=
'PATH',
133 default=
'clang-tidy',
134 help=
'path to clang-tidy binary')
135 parser.add_argument(
'-clang-apply-replacements-binary', metavar=
'PATH',
136 default=
'clang-apply-replacements',
137 help=
'path to clang-apply-replacements binary')
138 parser.add_argument(
'-checks', default=
None,
139 help=
'checks filter, when not specified, use clang-tidy '
141 parser.add_argument(
'-header-filter', default=
None,
142 help=
'regular expression matching the names of the '
143 'headers to output diagnostics from. Diagnostics from '
144 'the main file of each translation unit are always '
146 parser.add_argument(
'-j', type=int, default=0,
147 help=
'number of tidy instances to be run in parallel.')
148 parser.add_argument(
'files', nargs=
'*', default=[
'.*'],
149 help=
'files to be processed (regex on path)')
150 parser.add_argument(
'-fix', action=
'store_true', help=
'apply fix-its')
151 parser.add_argument(
'-format', action=
'store_true', help=
'Reformat code '
152 'after applying fixes')
153 parser.add_argument(
'-style', default=
'file', help=
'The style of reformat '
154 'code after applying fixes')
155 parser.add_argument(
'-p', dest=
'build_path',
156 help=
'Path used to read a compile command database.')
157 parser.add_argument(
'-extra-arg', dest=
'extra_arg',
158 action=
'append', default=[],
159 help=
'Additional argument to append to the compiler '
161 parser.add_argument(
'-extra-arg-before', dest=
'extra_arg_before',
162 action=
'append', default=[],
163 help=
'Additional argument to prepend to the compiler '
165 parser.add_argument(
'-quiet', action=
'store_true',
166 help=
'Run clang-tidy in quiet mode')
167 args = parser.parse_args()
169 db_path =
'compile_commands.json'
171 if args.build_path
is not None:
172 build_path = args.build_path
178 invocation = [args.clang_tidy_binary,
'-list-checks']
179 invocation.append(
'-p=' + build_path)
181 invocation.append(
'-checks=' + args.checks)
182 invocation.append(
'-')
183 print(subprocess.check_output(invocation))
185 print(
"Unable to run clang-tidy.", file=sys.stderr)
189 database = json.load(open(os.path.join(build_path, db_path)))
190 files = [entry[
'file']
for entry
in database]
194 max_task = multiprocessing.cpu_count()
199 tmpdir = tempfile.mkdtemp()
202 file_name_re = re.compile(
'|'.
join(args.files))
206 queue = Queue.Queue(max_task)
207 for _
in range(max_task):
208 t = threading.Thread(target=run_tidy,
209 args=(args, tmpdir, build_path, queue))
215 if file_name_re.search(name):
221 except KeyboardInterrupt:
224 print(
'\nCtrl-C detected, goodbye.')
226 shutil.rmtree(tmpdir)
230 print(
'Applying fixes ...')
231 successfully_applied =
False
235 successfully_applied =
True
237 print(
'Error applying fixes.\n', file=sys.stderr)
238 traceback.print_exc()
240 shutil.rmtree(tmpdir)
241 if not successfully_applied:
244 if __name__ ==
'__main__':
def find_compilation_database
def check_clang_apply_replacements_binary
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)