1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# Copyright (C) Google LLC, 2020 5# 6# Author: Nathan Huckleberry <nhuck@google.com> 7# 8"""A helper routine run clang-tidy and the clang static-analyzer on 9compile_commands.json. 10""" 11 12import argparse 13import json 14import multiprocessing 15import subprocess 16import sys 17 18 19def parse_arguments(): 20 """Set up and parses command-line arguments. 21 Returns: 22 args: Dict of parsed args 23 Has keys: [path, type] 24 """ 25 usage = """Run clang-tidy or the clang static-analyzer on a 26 compilation database.""" 27 parser = argparse.ArgumentParser(description=usage) 28 29 type_help = "Type of analysis to be performed" 30 parser.add_argument("type", 31 choices=["clang-tidy", "clang-analyzer"], 32 help=type_help) 33 path_help = "Path to the compilation database to parse" 34 parser.add_argument("path", type=str, help=path_help) 35 36 return parser.parse_args() 37 38 39def init(l, a): 40 global lock 41 global args 42 lock = l 43 args = a 44 45 46def run_analysis(entry): 47 # Disable all checks, then re-enable the ones we want 48 checks = [] 49 checks.append("-checks=-*") 50 if args.type == "clang-tidy": 51 checks.append("linuxkernel-*") 52 else: 53 checks.append("clang-analyzer-*") 54 checks.append("-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling") 55 p = subprocess.run(["clang-tidy", "-p", args.path, ",".join(checks), entry["file"]], 56 stdout=subprocess.PIPE, 57 stderr=subprocess.STDOUT, 58 cwd=entry["directory"]) 59 with lock: 60 sys.stderr.buffer.write(p.stdout) 61 62 63def main(): 64 try: 65 args = parse_arguments() 66 67 lock = multiprocessing.Lock() 68 pool = multiprocessing.Pool(initializer=init, initargs=(lock, args)) 69 # Read JSON data into the datastore variable 70 with open(args.path, "r") as f: 71 datastore = json.load(f) 72 pool.map(run_analysis, datastore) 73 except BrokenPipeError: 74 # Python flushes standard streams on exit; redirect remaining output 75 # to devnull to avoid another BrokenPipeError at shutdown 76 devnull = os.open(os.devnull, os.O_WRONLY) 77 os.dup2(devnull, sys.stdout.fileno()) 78 sys.exit(1) # Python exits with error code 1 on EPIPE 79 80 81if __name__ == "__main__": 82 main() 83