1*074075aeSMasahiro Yamada#!/usr/bin/env python3
26ad7cbc0SNathan Huckleberry# SPDX-License-Identifier: GPL-2.0
36ad7cbc0SNathan Huckleberry#
46ad7cbc0SNathan Huckleberry# Copyright (C) Google LLC, 2020
56ad7cbc0SNathan Huckleberry#
66ad7cbc0SNathan Huckleberry# Author: Nathan Huckleberry <nhuck@google.com>
76ad7cbc0SNathan Huckleberry#
86ad7cbc0SNathan Huckleberry"""A helper routine run clang-tidy and the clang static-analyzer on
96ad7cbc0SNathan Huckleberrycompile_commands.json.
106ad7cbc0SNathan Huckleberry"""
116ad7cbc0SNathan Huckleberry
126ad7cbc0SNathan Huckleberryimport argparse
136ad7cbc0SNathan Huckleberryimport json
146ad7cbc0SNathan Huckleberryimport multiprocessing
156ad7cbc0SNathan Huckleberryimport os
166ad7cbc0SNathan Huckleberryimport subprocess
176ad7cbc0SNathan Huckleberryimport sys
186ad7cbc0SNathan Huckleberry
196ad7cbc0SNathan Huckleberry
206ad7cbc0SNathan Huckleberrydef parse_arguments():
216ad7cbc0SNathan Huckleberry    """Set up and parses command-line arguments.
226ad7cbc0SNathan Huckleberry    Returns:
236ad7cbc0SNathan Huckleberry        args: Dict of parsed args
246ad7cbc0SNathan Huckleberry        Has keys: [path, type]
256ad7cbc0SNathan Huckleberry    """
266ad7cbc0SNathan Huckleberry    usage = """Run clang-tidy or the clang static-analyzer on a
276ad7cbc0SNathan Huckleberry        compilation database."""
286ad7cbc0SNathan Huckleberry    parser = argparse.ArgumentParser(description=usage)
296ad7cbc0SNathan Huckleberry
306ad7cbc0SNathan Huckleberry    type_help = "Type of analysis to be performed"
316ad7cbc0SNathan Huckleberry    parser.add_argument("type",
326ad7cbc0SNathan Huckleberry                        choices=["clang-tidy", "clang-analyzer"],
336ad7cbc0SNathan Huckleberry                        help=type_help)
346ad7cbc0SNathan Huckleberry    path_help = "Path to the compilation database to parse"
356ad7cbc0SNathan Huckleberry    parser.add_argument("path", type=str, help=path_help)
366ad7cbc0SNathan Huckleberry
376ad7cbc0SNathan Huckleberry    return parser.parse_args()
386ad7cbc0SNathan Huckleberry
396ad7cbc0SNathan Huckleberry
406ad7cbc0SNathan Huckleberrydef init(l, a):
416ad7cbc0SNathan Huckleberry    global lock
426ad7cbc0SNathan Huckleberry    global args
436ad7cbc0SNathan Huckleberry    lock = l
446ad7cbc0SNathan Huckleberry    args = a
456ad7cbc0SNathan Huckleberry
466ad7cbc0SNathan Huckleberry
476ad7cbc0SNathan Huckleberrydef run_analysis(entry):
486ad7cbc0SNathan Huckleberry    # Disable all checks, then re-enable the ones we want
496ad7cbc0SNathan Huckleberry    checks = "-checks=-*,"
506ad7cbc0SNathan Huckleberry    if args.type == "clang-tidy":
516ad7cbc0SNathan Huckleberry        checks += "linuxkernel-*"
526ad7cbc0SNathan Huckleberry    else:
536ad7cbc0SNathan Huckleberry        checks += "clang-analyzer-*"
546ad7cbc0SNathan Huckleberry    p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]],
556ad7cbc0SNathan Huckleberry                       stdout=subprocess.PIPE,
566ad7cbc0SNathan Huckleberry                       stderr=subprocess.STDOUT,
576ad7cbc0SNathan Huckleberry                       cwd=entry["directory"])
586ad7cbc0SNathan Huckleberry    with lock:
596ad7cbc0SNathan Huckleberry        sys.stderr.buffer.write(p.stdout)
606ad7cbc0SNathan Huckleberry
616ad7cbc0SNathan Huckleberry
626ad7cbc0SNathan Huckleberrydef main():
636ad7cbc0SNathan Huckleberry    args = parse_arguments()
646ad7cbc0SNathan Huckleberry
656ad7cbc0SNathan Huckleberry    lock = multiprocessing.Lock()
666ad7cbc0SNathan Huckleberry    pool = multiprocessing.Pool(initializer=init, initargs=(lock, args))
676ad7cbc0SNathan Huckleberry    # Read JSON data into the datastore variable
686ad7cbc0SNathan Huckleberry    with open(args.path, "r") as f:
696ad7cbc0SNathan Huckleberry        datastore = json.load(f)
706ad7cbc0SNathan Huckleberry        pool.map(run_analysis, datastore)
716ad7cbc0SNathan Huckleberry
726ad7cbc0SNathan Huckleberry
736ad7cbc0SNathan Huckleberryif __name__ == "__main__":
746ad7cbc0SNathan Huckleberry    main()
75