Commit | Line | Data |
---|---|---|
074075ae | 1 | #!/usr/bin/env python3 |
6ad7cbc0 NH |
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 | |
9 | compile_commands.json. | |
10 | """ | |
11 | ||
12 | import argparse | |
13 | import json | |
14 | import multiprocessing | |
6ad7cbc0 NH |
15 | import subprocess |
16 | import sys | |
17 | ||
18 | ||
19 | def 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 | ||
39 | def init(l, a): | |
40 | global lock | |
41 | global args | |
42 | lock = l | |
43 | args = a | |
44 | ||
45 | ||
46 | def run_analysis(entry): | |
47 | # Disable all checks, then re-enable the ones we want | |
04518e4c GDS |
48 | checks = [] |
49 | checks.append("-checks=-*") | |
6ad7cbc0 | 50 | if args.type == "clang-tidy": |
04518e4c | 51 | checks.append("linuxkernel-*") |
6ad7cbc0 | 52 | else: |
04518e4c GDS |
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"]], | |
6ad7cbc0 NH |
56 | stdout=subprocess.PIPE, |
57 | stderr=subprocess.STDOUT, | |
58 | cwd=entry["directory"]) | |
59 | with lock: | |
60 | sys.stderr.buffer.write(p.stdout) | |
61 | ||
62 | ||
63 | def main(): | |
87c7ee67 MY |
64 | try: |
65 | args = parse_arguments() | |
6ad7cbc0 | 66 | |
87c7ee67 MY |
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 | |
6ad7cbc0 NH |
79 | |
80 | ||
81 | if __name__ == "__main__": | |
82 | main() |