OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2017 The Chromium Authors. All rights reserved. | 2 # Copyright 2017 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Adds an analysis build step to invocations of the Clang C/C++ compiler. | 6 """Adds an analysis build step to invocations of the Clang C/C++ compiler. |
7 | 7 |
8 Usage: clang_static_analyzer_wrapper.py <compiler> [args...] | 8 Usage: clang_static_analyzer_wrapper.py <compiler> [args...] |
9 """ | 9 """ |
10 | 10 |
11 import argparse | 11 import argparse |
12 import fnmatch | 12 import fnmatch |
13 import itertools | 13 import itertools |
14 import os | 14 import os |
15 import sys | 15 import sys |
16 import wrapper_utils | 16 import wrapper_utils |
17 | 17 |
18 # Flags used to enable analysis for Clang invocations. | 18 # Flags used to enable analysis for Clang invocations. |
19 analyzer_enable_flags = [ | 19 analyzer_enable_flags = [ |
20 '--analyze', | 20 '--analyze', |
21 '-fdiagnostics-show-option', | |
22 ] | 21 ] |
23 | 22 |
24 # Flags used to configure the analyzer's behavior. | 23 # Flags used to configure the analyzer's behavior. |
25 analyzer_option_flags = [ | 24 analyzer_option_flags = [ |
| 25 '-fdiagnostics-show-option', |
26 '-analyzer-checker=cplusplus', | 26 '-analyzer-checker=cplusplus', |
27 '-analyzer-opt-analyze-nested-blocks', | 27 '-analyzer-opt-analyze-nested-blocks', |
28 '-analyzer-eagerly-assume', | 28 '-analyzer-eagerly-assume', |
29 '-analyzer-output=text', | 29 '-analyzer-output=text', |
30 '-analyzer-config', | 30 '-analyzer-config', |
31 'suppress-c++-stdlib=true', | 31 'suppress-c++-stdlib=true', |
32 | 32 |
33 # List of checkers to execute. | 33 # List of checkers to execute. |
34 # The full list of checkers can be found at | 34 # The full list of checkers can be found at |
35 # https://clang-analyzer.llvm.org/available_checks.html. | 35 # https://clang-analyzer.llvm.org/available_checks.html. |
36 '-analyzer-checker=core', | 36 '-analyzer-checker=core', |
37 '-analyzer-checker=unix', | 37 '-analyzer-checker=unix', |
38 '-analyzer-checker=deadcode', | 38 '-analyzer-checker=deadcode', |
39 ] | 39 ] |
40 | 40 |
41 | 41 |
| 42 # Prepends every element of a list |args| with |token|. |
| 43 # e.g. ['-analyzer-foo', '-analyzer-bar'] => ['-Xanalyzer', '-analyzer-foo', |
| 44 # '-Xanalyzer', '-analyzer-bar'] |
| 45 def interleave_args(args, token): |
| 46 return list(sum(zip([token] * len(args), args), ())) |
| 47 |
| 48 |
42 def main(): | 49 def main(): |
43 args = sys.argv[1:] | 50 parser = argparse.ArgumentParser() |
44 assert args | 51 parser.add_argument('--mode', |
| 52 choices=['clang', 'cl'], |
| 53 required=True, |
| 54 help='Specifies the compiler argument convention to use.') |
| 55 parser.add_argument('args', nargs=argparse.REMAINDER) |
| 56 parsed_args = parser.parse_args() |
45 | 57 |
46 # Build the object file and proceed with analysis if it is buildable. | 58 prefix = '-Xclang' if parsed_args.mode == 'cl' else '-Xanalyzer' |
| 59 cmd = parsed_args.args + analyzer_enable_flags + \ |
| 60 interleave_args(analyzer_option_flags, prefix) |
47 returncode, stderr = wrapper_utils.CaptureCommandStderr( | 61 returncode, stderr = wrapper_utils.CaptureCommandStderr( |
48 wrapper_utils.CommandToRun(args)) | 62 wrapper_utils.CommandToRun(cmd)) |
49 sys.stderr.write(stderr) | |
50 if returncode != 0: | |
51 return returncode | |
52 | |
53 # Now run the analyzer. | |
54 | |
55 # Interleave 'analyzer_option_flags' flags w/'-Xanalyzer' so that Clang | |
56 # passes them to the analysis tool. | |
57 # e.g. ['-analyzer-foo', '-analyzer-bar'] => ['-Xanalyzer', '-analyzer-foo', | |
58 # '-Xanalyzer', '-analyzer-bar'] | |
59 interleaved_analyzer_flags = list(sum(zip( | |
60 ['-Xanalyzer'] * len(analyzer_option_flags), | |
61 analyzer_option_flags), ())) | |
62 returncode, stderr = wrapper_utils.CaptureCommandStderr( | |
63 wrapper_utils.CommandToRun(args + analyzer_enable_flags + | |
64 interleaved_analyzer_flags)) | |
65 sys.stderr.write(stderr) | 63 sys.stderr.write(stderr) |
66 if returncode != 0: | 64 if returncode != 0: |
67 sys.stderr.write( | 65 sys.stderr.write( |
68 """WARNING! The Clang static analyzer exited with error code %d. | 66 """WARNING! The Clang static analyzer exited with error code %d. |
69 Please share the error details in crbug.com/695243 if this looks like | 67 Please share the error details in crbug.com/695243 if this looks like |
70 a new regression.\n""" % (returncode)) | 68 a new regression.\n""" % (returncode)) |
71 | 69 |
72 return 0 | 70 returncode, stderr = wrapper_utils.CaptureCommandStderr( |
| 71 wrapper_utils.CommandToRun(parsed_args.args)) |
| 72 sys.stderr.write(stderr) |
| 73 |
| 74 return returncode |
73 | 75 |
74 if __name__ == '__main__': | 76 if __name__ == '__main__': |
75 sys.exit(main()) | 77 sys.exit(main()) |
OLD | NEW |