1#!/usr/bin/env python3 2 3# Copyright 2019, VIXL authors 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 9# * Redistributions of source code must retain the above copyright notice, 10# this list of conditions and the following disclaimer. 11# * Redistributions in binary form must reproduce the above copyright notice, 12# this list of conditions and the following disclaimer in the documentation 13# and/or other materials provided with the distribution. 14# * Neither the name of ARM Limited nor the names of its contributors may be 15# used to endorse or promote products derived from this software without 16# specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28import argparse 29import multiprocessing 30import os 31import re 32import sys 33import subprocess 34 35from clang_format import detect_clang_tool 36from threaded_tests import Test, TestQueue 37import config 38import printer 39import util 40 41DEFAULT_CLANG_TIDY = 'clang-tidy' 42 43def BuildOptions(): 44 parser = argparse.ArgumentParser( 45 description = '''This tool runs `clang-tidy` on C++ files.''', 46 # Print default values. 47 formatter_class = argparse.ArgumentDefaultsHelpFormatter) 48 parser.add_argument('files', nargs='*') 49 parser.add_argument('--jobs', '-j', metavar='N', type=int, nargs='?', 50 default=multiprocessing.cpu_count(), 51 const=multiprocessing.cpu_count(), 52 help='''Runs the tests using N jobs. If the option is set 53 but no value is provided, the script will use as many jobs 54 as it thinks useful.''') 55 parser.add_argument('--clang-tidy', default=DEFAULT_CLANG_TIDY, 56 help='Path to clang-tidy.') 57 return parser.parse_args() 58 59def FilterClangTidyLines(lines): 60 out = [] 61 print_context = False 62 for line in lines: 63 if ("Error: no checks enabled" in line) or ("USAGE" in line): 64 # We've incorrectly invoked or configured clang-tidy. This should never 65 # happen, but it if it does, make sure that the test fails. 66 return line 67 elif "error:" in line: 68 out.append(line) 69 print_context = True 70 elif "warning:" in line: 71 out.append(line) 72 print_context = True 73 elif print_context: 74 out.append(line) 75 return "\n".join(out) 76 77def FilterFiles(list_files): 78 return [x for x in list_files if x.endswith('.cc')] 79 80def RunTest(test): 81 cmd = " ".join(test.args['command']) 82 rc, p_out = util.getstatusoutput(cmd) 83 if rc != 0: 84 # This usually happens when the compiler hits a '#error' because of 85 # a missing define. 86 printer.Print("%sFATAL ERROR: failed to run command '%s': %s%s" % 87 (printer.COLOUR_RED, cmd, p_out, printer.NO_COLOUR)) 88 p_out = FilterClangTidyLines(p_out.split('\n')) 89 90 failed = (len(p_out) > 0) or (rc != 0) 91 92 if failed: 93 with Test.n_tests_failed.get_lock(): Test.n_tests_failed.value += 1 94 else: 95 with Test.n_tests_passed.get_lock(): Test.n_tests_passed.value += 1 96 97 printer.__print_lock__.acquire() 98 99 printer.UpdateProgress(test.shared.start_time, 100 Test.n_tests_passed.value, 101 Test.n_tests_failed.value, 102 test.shared.n_tests, 103 Test.n_tests_skipped.value, 104 test.shared.n_known_failures, 105 test.name, 106 prevent_next_overwrite = failed , 107 has_lock = True, 108 prefix = test.shared.progress_prefix) 109 110 if failed: 111 printer.Print(printer.COLOUR_RED + 'FAILED: '+ cmd + printer.NO_COLOUR, 112 has_lock = True) 113 printer.Print(p_out, has_lock = True) 114 115 printer.__print_lock__.release() 116 117def ClangTidyFiles(files, clang_tidy, jobs = 1, progress_prefix = ''): 118 119 clang_tidy = detect_clang_tool("clang-tidy") 120 121 if not clang_tidy: 122 error_message = "clang-tidy not found. Please ensure it " \ 123 "is installed, in your PATH and the correct version." 124 print(printer.COLOUR_RED + error_message + printer.NO_COLOUR) 125 return -1 126 127 opts = ['--', '-DVIXL_INCLUDE_TARGET_AARCH64', '-DVIXL_CODE_BUFFER_MALLOC', 128 '-DVIXL_DEBUG','-DVIXL_INCLUDE_SIMULATOR_AARCH64', 129 '-DVIXL_INCLUDE_TARGET_A32','-DVIXL_INCLUDE_TARGET_T32', 130 '-DVIXL_INCLUDE_TARGET_A64'] 131 opts += ['-I%s' % config.dir_src_vixl] 132 opts += ['-I%s' % config.dir_tests] 133 opts += ['-I%s' % config.dir_aarch64_examples] 134 opts += ['-I%s' % config.dir_aarch32_examples] 135 136 to_check = FilterFiles(files) 137 printer.Print("clang-tidy: %d files to check" % len(to_check)) 138 139 queue = TestQueue(prefix = progress_prefix) 140 141 for file in to_check: 142 for cpp_version in config.tested_cpp_standards: 143 command = [clang_tidy, file] + opts + ['-std=%s' % cpp_version] 144 queue.AddTest(file, command=command) 145 146 return queue.Run(jobs, True, RunTest) 147 148if __name__ == '__main__': 149 # Parse the arguments. 150 args = BuildOptions() 151 files = args.files or util.get_source_files() 152 153 rc = ClangTidyFiles(files, args.clang_tidy, args.jobs) 154 155 sys.exit(rc) 156