| 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 |