2 # SPDX-License-Identifier: GPL-2.0
4 # Copyright (C) Google LLC, 2020
6 # Author: Nathan Huckleberry <nhuck@google.com>
8 """A helper routine run clang-tidy and the clang static-analyzer on
14 import multiprocessing
19 def parse_arguments():
20 """Set up and parses command-line arguments.
22 args: Dict of parsed args
23 Has keys: [path, type]
25 usage
= """Run clang-tidy or the clang static-analyzer on a
26 compilation database."""
27 parser
= argparse
.ArgumentParser(description
=usage
)
29 type_help
= "Type of analysis to be performed"
30 parser
.add_argument("type",
31 choices
=["clang-tidy", "clang-analyzer"],
33 path_help
= "Path to the compilation database to parse"
34 parser
.add_argument("path", type=str, help=path_help
)
36 checks_help
= "Checks to pass to the analysis"
37 parser
.add_argument("-checks", type=str, default
=None, help=checks_help
)
38 header_filter_help
= "Pass the -header-filter value to the tool"
39 parser
.add_argument("-header-filter", type=str, default
=None, help=header_filter_help
)
41 return parser
.parse_args()
51 def run_analysis(entry
):
52 # Disable all checks, then re-enable the ones we want
56 checks
= args
.checks
.split(',')
59 if args
.type == "clang-tidy":
60 checks
.append("linuxkernel-*")
62 checks
.append("clang-analyzer-*")
63 checks
.append("-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling")
65 if not file.endswith(".c") and not file.endswith(".cpp"):
67 print(f
"Skipping non-C file: '{file}'", file=sys
.stderr
)
69 pargs
= ["clang-tidy", "-p", args
.path
, "-checks=" + ",".join(checks
)]
70 if args
.header_filter
:
71 pargs
.append("-header-filter=" + args
.header_filter
)
73 p
= subprocess
.run(pargs
,
74 stdout
=subprocess
.PIPE
,
75 stderr
=subprocess
.STDOUT
,
76 cwd
=entry
["directory"])
78 sys
.stderr
.buffer.write(p
.stdout
)
83 args
= parse_arguments()
85 lock
= multiprocessing
.Lock()
86 pool
= multiprocessing
.Pool(initializer
=init
, initargs
=(lock
, args
))
87 # Read JSON data into the datastore variable
88 with
open(args
.path
, "r") as f
:
89 datastore
= json
.load(f
)
90 pool
.map(run_analysis
, datastore
)
91 except BrokenPipeError
:
92 # Python flushes standard streams on exit; redirect remaining output
93 # to devnull to avoid another BrokenPipeError at shutdown
94 devnull
= os
.open(os
.devnull
, os
.O_WRONLY
)
95 os
.dup2(devnull
, sys
.stdout
.fileno())
96 sys
.exit(1) # Python exits with error code 1 on EPIPE
99 if __name__
== "__main__":