22#
33#===- run-clang-tidy.py - Parallel clang-tidy runner ---------*- python -*--===#
44#
5- # The LLVM Compiler Infrastructure
6- #
7- # This file is distributed under the University of Illinois Open Source
8- # License. See LICENSE.TXT for details.
5+ # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6+ # See https://llvm.org/LICENSE.txt for license information.
7+ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
98#
109#===------------------------------------------------------------------------===#
1110# FIXME: Integrate with clang-tidy-diff.py
4847import tempfile
4948import threading
5049import traceback
51- import yaml
50+
51+ try :
52+ import yaml
53+ except ImportError :
54+ yaml = None
5255
5356is_py2 = sys .version [0 ] == '2'
5457
@@ -81,9 +84,6 @@ def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
8184 start = [clang_tidy_binary ]
8285 if header_filter is not None :
8386 start .append ('-header-filter=' + header_filter )
84- else :
85- # Show warnings in all in-project headers by default.
86- start .append ('-header-filter=^' + build_path + '/.*' )
8787 if checks :
8888 start .append ('-checks=' + checks )
8989 if tmpdir is not None :
@@ -153,18 +153,24 @@ def apply_fixes(args, tmpdir):
153153 subprocess .call (invocation )
154154
155155
156- def run_tidy (args , tmpdir , build_path , queue , failed_files ):
156+ def run_tidy (args , tmpdir , build_path , queue , lock , failed_files ):
157157 """Takes filenames out of queue and runs clang-tidy on them."""
158158 while True :
159159 name = queue .get ()
160160 invocation = get_tidy_invocation (name , args .clang_tidy_binary , args .checks ,
161161 tmpdir , build_path , args .header_filter ,
162162 args .extra_arg , args .extra_arg_before ,
163163 args .quiet , args .config )
164- sys .stdout .write (' ' .join (invocation ) + '\n ' )
165- return_code = subprocess .call (invocation )
166- if return_code != 0 :
164+
165+ proc = subprocess .Popen (invocation , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
166+ output , err = proc .communicate ()
167+ if proc .returncode != 0 :
167168 failed_files .append (name )
169+ with lock :
170+ sys .stdout .write (' ' .join (invocation ) + '\n ' + output .decode ('utf-8' ))
171+ if len (err ) > 0 :
172+ sys .stdout .flush ()
173+ sys .stderr .write (err .decode ('utf-8' ))
168174 queue .task_done ()
169175
170176
@@ -195,9 +201,10 @@ def main():
195201 'headers to output diagnostics from. Diagnostics from '
196202 'the main file of each translation unit are always '
197203 'displayed.' )
198- parser .add_argument ('-export-fixes' , metavar = 'filename' , dest = 'export_fixes' ,
199- help = 'Create a yaml file to store suggested fixes in, '
200- 'which can be applied with clang-apply-replacements.' )
204+ if yaml :
205+ parser .add_argument ('-export-fixes' , metavar = 'filename' , dest = 'export_fixes' ,
206+ help = 'Create a yaml file to store suggested fixes in, '
207+ 'which can be applied with clang-apply-replacements.' )
201208 parser .add_argument ('-j' , type = int , default = 0 ,
202209 help = 'number of tidy instances to be run in parallel.' )
203210 parser .add_argument ('files' , nargs = '*' , default = ['.*' ],
@@ -235,7 +242,12 @@ def main():
235242 if args .checks :
236243 invocation .append ('-checks=' + args .checks )
237244 invocation .append ('-' )
238- subprocess .check_call (invocation )
245+ if args .quiet :
246+ # Even with -quiet we still want to check if we can call clang-tidy.
247+ with open (os .devnull , 'w' ) as dev_null :
248+ subprocess .check_call (invocation , stdout = dev_null )
249+ else :
250+ subprocess .check_call (invocation )
239251 except :
240252 print ("Unable to run clang-tidy." , file = sys .stderr )
241253 sys .exit (1 )
@@ -250,7 +262,7 @@ def main():
250262 max_task = multiprocessing .cpu_count ()
251263
252264 tmpdir = None
253- if args .fix or args .export_fixes :
265+ if args .fix or ( yaml and args .export_fixes ) :
254266 check_clang_apply_replacements_binary (args )
255267 tmpdir = tempfile .mkdtemp ()
256268
@@ -263,9 +275,10 @@ def main():
263275 task_queue = queue .Queue (max_task )
264276 # List of files with a non-zero return code.
265277 failed_files = []
278+ lock = threading .Lock ()
266279 for _ in range (max_task ):
267280 t = threading .Thread (target = run_tidy ,
268- args = (args , tmpdir , build_path , task_queue , failed_files ))
281+ args = (args , tmpdir , build_path , task_queue , lock , failed_files ))
269282 t .daemon = True
270283 t .start ()
271284
@@ -287,7 +300,7 @@ def main():
287300 shutil .rmtree (tmpdir )
288301 os .kill (0 , 9 )
289302
290- if args .export_fixes :
303+ if yaml and args .export_fixes :
291304 print ('Writing fixes to ' + args .export_fixes + ' ...' )
292305 try :
293306 merge_replacement_files (tmpdir , args .export_fixes )
0 commit comments