Index: clang-tidy/tool/run-clang-tidy.py =================================================================== --- clang-tidy/tool/run-clang-tidy.py +++ clang-tidy/tool/run-clang-tidy.py @@ -153,7 +153,7 @@ subprocess.call(invocation) -def run_tidy(args, tmpdir, build_path, queue): +def run_tidy(args, tmpdir, build_path, queue, failed_files): """Takes filenames out of queue and runs clang-tidy on them.""" while True: name = queue.get() @@ -162,7 +162,9 @@ args.extra_arg, args.extra_arg_before, args.quiet, args.config) sys.stdout.write(' '.join(invocation) + '\n') - subprocess.call(invocation) + return_code = subprocess.call(invocation) + if return_code != 0: + failed_files.append(name) queue.task_done() @@ -255,12 +257,15 @@ # Build up a big regexy filter from all command line arguments. file_name_re = re.compile('|'.join(args.files)) + return_code = 0 try: # Spin up a bunch of tidy-launching threads. task_queue = queue.Queue(max_task) + # List of files with a non-zero return code. + failed_files = [] for _ in range(max_task): t = threading.Thread(target=run_tidy, - args=(args, tmpdir, build_path, task_queue)) + args=(args, tmpdir, build_path, task_queue, failed_files)) t.daemon = True t.start() @@ -271,6 +276,8 @@ # Wait for all threads to be done. task_queue.join() + if len(failed_files): + return_code = 1 except KeyboardInterrupt: # This is a sad hack. Unfortunately subprocess goes @@ -280,7 +287,6 @@ shutil.rmtree(tmpdir) os.kill(0, 9) - return_code = 0 if args.export_fixes: print('Writing fixes to ' + args.export_fixes + ' ...') try: Index: test/clang-tidy/run-clang-tidy.cpp =================================================================== --- test/clang-tidy/run-clang-tidy.cpp +++ test/clang-tidy/run-clang-tidy.cpp @@ -0,0 +1,14 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json +// RUN: echo "Checks: '-*,modernize-use-auto'" > %t/.clang-tidy +// RUN: echo "WarningsAsErrors: '*'" >> %t/.clang-tidy +// RUN: cp "%s" "%t/test.cpp" +// RUN: cd "%t" +// RUN: not %run_clang_tidy "%t/test.cpp" + +int main() +{ + int* x = new int(); + delete x; +} Index: test/lit.cfg =================================================================== --- test/lit.cfg +++ test/lit.cfg @@ -129,6 +129,11 @@ config.substitutions.append( ('%clang_tidy_diff', '%s %s' % (config.python_executable, clang_tidy_diff)) ) + run_clang_tidy = os.path.join( + config.test_source_root, "..", "clang-tidy", "tool", "run-clang-tidy.py") + config.substitutions.append( + ('%run_clang_tidy', + '%s %s' % (config.python_executable, run_clang_tidy)) ) else: # exclude the clang-tidy test directory config.excludes.append('clang-tidy')