18c2ecf20Sopenharmony_ci#!/usr/bin/env python3 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 38c2ecf20Sopenharmony_ci# 48c2ecf20Sopenharmony_ci# Copyright (C) Google LLC, 2020 58c2ecf20Sopenharmony_ci# 68c2ecf20Sopenharmony_ci# Author: Nathan Huckleberry <nhuck@google.com> 78c2ecf20Sopenharmony_ci# 88c2ecf20Sopenharmony_ci"""A helper routine run clang-tidy and the clang static-analyzer on 98c2ecf20Sopenharmony_cicompile_commands.json. 108c2ecf20Sopenharmony_ci""" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciimport argparse 138c2ecf20Sopenharmony_ciimport json 148c2ecf20Sopenharmony_ciimport multiprocessing 158c2ecf20Sopenharmony_ciimport os 168c2ecf20Sopenharmony_ciimport subprocess 178c2ecf20Sopenharmony_ciimport sys 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cidef parse_arguments(): 218c2ecf20Sopenharmony_ci """Set up and parses command-line arguments. 228c2ecf20Sopenharmony_ci Returns: 238c2ecf20Sopenharmony_ci args: Dict of parsed args 248c2ecf20Sopenharmony_ci Has keys: [path, type] 258c2ecf20Sopenharmony_ci """ 268c2ecf20Sopenharmony_ci usage = """Run clang-tidy or the clang static-analyzer on a 278c2ecf20Sopenharmony_ci compilation database.""" 288c2ecf20Sopenharmony_ci parser = argparse.ArgumentParser(description=usage) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci type_help = "Type of analysis to be performed" 318c2ecf20Sopenharmony_ci parser.add_argument("type", 328c2ecf20Sopenharmony_ci choices=["clang-tidy", "clang-analyzer"], 338c2ecf20Sopenharmony_ci help=type_help) 348c2ecf20Sopenharmony_ci path_help = "Path to the compilation database to parse" 358c2ecf20Sopenharmony_ci parser.add_argument("path", type=str, help=path_help) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return parser.parse_args() 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cidef init(l, a): 418c2ecf20Sopenharmony_ci global lock 428c2ecf20Sopenharmony_ci global args 438c2ecf20Sopenharmony_ci lock = l 448c2ecf20Sopenharmony_ci args = a 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cidef run_analysis(entry): 488c2ecf20Sopenharmony_ci # Disable all checks, then re-enable the ones we want 498c2ecf20Sopenharmony_ci checks = "-checks=-*," 508c2ecf20Sopenharmony_ci if args.type == "clang-tidy": 518c2ecf20Sopenharmony_ci checks += "linuxkernel-*" 528c2ecf20Sopenharmony_ci else: 538c2ecf20Sopenharmony_ci checks += "clang-analyzer-*" 548c2ecf20Sopenharmony_ci p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]], 558c2ecf20Sopenharmony_ci stdout=subprocess.PIPE, 568c2ecf20Sopenharmony_ci stderr=subprocess.STDOUT, 578c2ecf20Sopenharmony_ci cwd=entry["directory"]) 588c2ecf20Sopenharmony_ci with lock: 598c2ecf20Sopenharmony_ci sys.stderr.buffer.write(p.stdout) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cidef main(): 638c2ecf20Sopenharmony_ci try: 648c2ecf20Sopenharmony_ci args = parse_arguments() 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci lock = multiprocessing.Lock() 678c2ecf20Sopenharmony_ci pool = multiprocessing.Pool(initializer=init, initargs=(lock, args)) 688c2ecf20Sopenharmony_ci # Read JSON data into the datastore variable 698c2ecf20Sopenharmony_ci with open(args.path, "r") as f: 708c2ecf20Sopenharmony_ci datastore = json.load(f) 718c2ecf20Sopenharmony_ci pool.map(run_analysis, datastore) 728c2ecf20Sopenharmony_ci except BrokenPipeError: 738c2ecf20Sopenharmony_ci # Python flushes standard streams on exit; redirect remaining output 748c2ecf20Sopenharmony_ci # to devnull to avoid another BrokenPipeError at shutdown 758c2ecf20Sopenharmony_ci devnull = os.open(os.devnull, os.O_WRONLY) 768c2ecf20Sopenharmony_ci os.dup2(devnull, sys.stdout.fileno()) 778c2ecf20Sopenharmony_ci sys.exit(1) # Python exits with error code 1 on EPIPE 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciif __name__ == "__main__": 818c2ecf20Sopenharmony_ci main() 82