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