#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0 # # Copyright (C) Google LLC, 2020 # # Author: Nathan Huckleberry <nhuck@google.com> # """A helper routine run clang-tidy and the clang static-analyzer on compile_commands.json. """ import argparse import json import multiprocessing import subprocess import sys def parse_arguments(): """Set up and parses command-line arguments. Returns: args: Dict of parsed args Has keys: [path, type] """ usage = """Run clang-tidy or the clang static-analyzer on a compilation database.""" parser = argparse.ArgumentParser(description=usage) type_help = "Type of analysis to be performed" parser.add_argument("type", choices=["clang-tidy", "clang-analyzer"], help=type_help) path_help = "Path to the compilation database to parse" parser.add_argument("path", type=str, help=path_help) return parser.parse_args() def init(l, a): global lock global args lock = l args = a def run_analysis(entry): # Disable all checks, then re-enable the ones we want checks = [] checks.append("-checks=-*") if args.type == "clang-tidy": checks.append("linuxkernel-*") else: checks.append("clang-analyzer-*") checks.append("-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling") p = subprocess.run(["clang-tidy", "-p", args.path, ",".join(checks), entry["file"]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=entry["directory"]) with lock: sys.stderr.buffer.write(p.stdout) def main(): try: args = parse_arguments() lock = multiprocessing.Lock() pool = multiprocessing.Pool(initializer=init, initargs=(lock, args)) # Read JSON data into the datastore variable with open(args.path, "r") as f: datastore = json.load(f) pool.map(run_analysis, datastore) except BrokenPipeError: # Python flushes standard streams on exit; redirect remaining output # to devnull to avoid another BrokenPipeError at shutdown devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) sys.exit(1) # Python exits with error code 1 on EPIPE if __name__ == "__main__": main()