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