1d9cf8291SDaniel Hwang# -*- coding: utf-8 -*- 2d9cf8291SDaniel Hwang# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3d9cf8291SDaniel Hwang# See https://llvm.org/LICENSE.txt for license information. 4d9cf8291SDaniel Hwang# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5d9cf8291SDaniel Hwang""" This module parses and validates arguments for command-line interfaces. 6d9cf8291SDaniel Hwang 7d9cf8291SDaniel HwangIt uses argparse module to create the command line parser. (This library is 8d9cf8291SDaniel Hwangin the standard python library since 3.2 and backported to 2.7, but not 9d9cf8291SDaniel Hwangearlier.) 10d9cf8291SDaniel Hwang 11d9cf8291SDaniel HwangIt also implements basic validation methods, related to the command. 12d9cf8291SDaniel HwangValidations are mostly calling specific help methods, or mangling values. 13d9cf8291SDaniel Hwang""" 14d9cf8291SDaniel Hwangfrom __future__ import absolute_import, division, print_function 15d9cf8291SDaniel Hwang 16d9cf8291SDaniel Hwangimport os 17d9cf8291SDaniel Hwangimport sys 18d9cf8291SDaniel Hwangimport argparse 19d9cf8291SDaniel Hwangimport logging 20d9cf8291SDaniel Hwangimport tempfile 21d9cf8291SDaniel Hwangfrom libscanbuild import reconfigure_logging, CtuConfig 22d9cf8291SDaniel Hwangfrom libscanbuild.clang import get_checkers, is_ctu_capable 23d9cf8291SDaniel Hwang 24*dd3c26a0STobias Hieta__all__ = [ 25*dd3c26a0STobias Hieta "parse_args_for_intercept_build", 26*dd3c26a0STobias Hieta "parse_args_for_analyze_build", 27*dd3c26a0STobias Hieta "parse_args_for_scan_build", 28*dd3c26a0STobias Hieta] 29d9cf8291SDaniel Hwang 30d9cf8291SDaniel Hwang 31d9cf8291SDaniel Hwangdef parse_args_for_intercept_build(): 32d9cf8291SDaniel Hwang """Parse and validate command-line arguments for intercept-build.""" 33d9cf8291SDaniel Hwang 34d9cf8291SDaniel Hwang parser = create_intercept_parser() 35d9cf8291SDaniel Hwang args = parser.parse_args() 36d9cf8291SDaniel Hwang 37d9cf8291SDaniel Hwang reconfigure_logging(args.verbose) 38*dd3c26a0STobias Hieta logging.debug("Raw arguments %s", sys.argv) 39d9cf8291SDaniel Hwang 40d9cf8291SDaniel Hwang # short validation logic 41d9cf8291SDaniel Hwang if not args.build: 42*dd3c26a0STobias Hieta parser.error(message="missing build command") 43d9cf8291SDaniel Hwang 44*dd3c26a0STobias Hieta logging.debug("Parsed arguments: %s", args) 45d9cf8291SDaniel Hwang return args 46d9cf8291SDaniel Hwang 47d9cf8291SDaniel Hwang 48d9cf8291SDaniel Hwangdef parse_args_for_analyze_build(): 49d9cf8291SDaniel Hwang """Parse and validate command-line arguments for analyze-build.""" 50d9cf8291SDaniel Hwang 51d9cf8291SDaniel Hwang from_build_command = False 52d9cf8291SDaniel Hwang parser = create_analyze_parser(from_build_command) 53d9cf8291SDaniel Hwang args = parser.parse_args() 54d9cf8291SDaniel Hwang 55d9cf8291SDaniel Hwang reconfigure_logging(args.verbose) 56*dd3c26a0STobias Hieta logging.debug("Raw arguments %s", sys.argv) 57d9cf8291SDaniel Hwang 58d9cf8291SDaniel Hwang normalize_args_for_analyze(args, from_build_command) 59d9cf8291SDaniel Hwang validate_args_for_analyze(parser, args, from_build_command) 60*dd3c26a0STobias Hieta logging.debug("Parsed arguments: %s", args) 61d9cf8291SDaniel Hwang return args 62d9cf8291SDaniel Hwang 63d9cf8291SDaniel Hwang 64d9cf8291SDaniel Hwangdef parse_args_for_scan_build(): 65d9cf8291SDaniel Hwang """Parse and validate command-line arguments for scan-build.""" 66d9cf8291SDaniel Hwang 67d9cf8291SDaniel Hwang from_build_command = True 68d9cf8291SDaniel Hwang parser = create_analyze_parser(from_build_command) 69d9cf8291SDaniel Hwang args = parser.parse_args() 70d9cf8291SDaniel Hwang 71d9cf8291SDaniel Hwang reconfigure_logging(args.verbose) 72*dd3c26a0STobias Hieta logging.debug("Raw arguments %s", sys.argv) 73d9cf8291SDaniel Hwang 74d9cf8291SDaniel Hwang normalize_args_for_analyze(args, from_build_command) 75d9cf8291SDaniel Hwang validate_args_for_analyze(parser, args, from_build_command) 76*dd3c26a0STobias Hieta logging.debug("Parsed arguments: %s", args) 77d9cf8291SDaniel Hwang return args 78d9cf8291SDaniel Hwang 79d9cf8291SDaniel Hwang 80d9cf8291SDaniel Hwangdef normalize_args_for_analyze(args, from_build_command): 81d9cf8291SDaniel Hwang """Normalize parsed arguments for analyze-build and scan-build. 82d9cf8291SDaniel Hwang 83d9cf8291SDaniel Hwang :param args: Parsed argument object. (Will be mutated.) 84d9cf8291SDaniel Hwang :param from_build_command: Boolean value tells is the command suppose 85d9cf8291SDaniel Hwang to run the analyzer against a build command or a compilation db.""" 86d9cf8291SDaniel Hwang 87d9cf8291SDaniel Hwang # make plugins always a list. (it might be None when not specified.) 88d9cf8291SDaniel Hwang if args.plugins is None: 89d9cf8291SDaniel Hwang args.plugins = [] 90d9cf8291SDaniel Hwang 91d9cf8291SDaniel Hwang # make exclude directory list unique and absolute. 92d9cf8291SDaniel Hwang uniq_excludes = set(os.path.abspath(entry) for entry in args.excludes) 93d9cf8291SDaniel Hwang args.excludes = list(uniq_excludes) 94d9cf8291SDaniel Hwang 95d9cf8291SDaniel Hwang # because shared codes for all tools, some common used methods are 96d9cf8291SDaniel Hwang # expecting some argument to be present. so, instead of query the args 97d9cf8291SDaniel Hwang # object about the presence of the flag, we fake it here. to make those 98d9cf8291SDaniel Hwang # methods more readable. (it's an arguable choice, took it only for those 99d9cf8291SDaniel Hwang # which have good default value.) 100d9cf8291SDaniel Hwang if from_build_command: 101d9cf8291SDaniel Hwang # add cdb parameter invisibly to make report module working. 102*dd3c26a0STobias Hieta args.cdb = "compile_commands.json" 103d9cf8291SDaniel Hwang 104d9cf8291SDaniel Hwang # Make ctu_dir an abspath as it is needed inside clang 105*dd3c26a0STobias Hieta if ( 106*dd3c26a0STobias Hieta not from_build_command 107*dd3c26a0STobias Hieta and hasattr(args, "ctu_phases") 108*dd3c26a0STobias Hieta and hasattr(args.ctu_phases, "dir") 109*dd3c26a0STobias Hieta ): 110d9cf8291SDaniel Hwang args.ctu_dir = os.path.abspath(args.ctu_dir) 111d9cf8291SDaniel Hwang 112d9cf8291SDaniel Hwang 113d9cf8291SDaniel Hwangdef validate_args_for_analyze(parser, args, from_build_command): 114d9cf8291SDaniel Hwang """Command line parsing is done by the argparse module, but semantic 115d9cf8291SDaniel Hwang validation still needs to be done. This method is doing it for 116d9cf8291SDaniel Hwang analyze-build and scan-build commands. 117d9cf8291SDaniel Hwang 118d9cf8291SDaniel Hwang :param parser: The command line parser object. 119d9cf8291SDaniel Hwang :param args: Parsed argument object. 120d9cf8291SDaniel Hwang :param from_build_command: Boolean value tells is the command suppose 121d9cf8291SDaniel Hwang to run the analyzer against a build command or a compilation db. 122d9cf8291SDaniel Hwang :return: No return value, but this call might throw when validation 123d9cf8291SDaniel Hwang fails.""" 124d9cf8291SDaniel Hwang 125d9cf8291SDaniel Hwang if args.help_checkers_verbose: 126d9cf8291SDaniel Hwang print_checkers(get_checkers(args.clang, args.plugins)) 127d9cf8291SDaniel Hwang parser.exit(status=0) 128d9cf8291SDaniel Hwang elif args.help_checkers: 129d9cf8291SDaniel Hwang print_active_checkers(get_checkers(args.clang, args.plugins)) 130d9cf8291SDaniel Hwang parser.exit(status=0) 131d9cf8291SDaniel Hwang elif from_build_command and not args.build: 132*dd3c26a0STobias Hieta parser.error(message="missing build command") 133d9cf8291SDaniel Hwang elif not from_build_command and not os.path.exists(args.cdb): 134*dd3c26a0STobias Hieta parser.error(message="compilation database is missing") 135d9cf8291SDaniel Hwang 136d9cf8291SDaniel Hwang # If the user wants CTU mode 137*dd3c26a0STobias Hieta if ( 138*dd3c26a0STobias Hieta not from_build_command 139*dd3c26a0STobias Hieta and hasattr(args, "ctu_phases") 140*dd3c26a0STobias Hieta and hasattr(args.ctu_phases, "dir") 141*dd3c26a0STobias Hieta ): 142d9cf8291SDaniel Hwang # If CTU analyze_only, the input directory should exist 143*dd3c26a0STobias Hieta if ( 144*dd3c26a0STobias Hieta args.ctu_phases.analyze 145*dd3c26a0STobias Hieta and not args.ctu_phases.collect 146*dd3c26a0STobias Hieta and not os.path.exists(args.ctu_dir) 147*dd3c26a0STobias Hieta ): 148*dd3c26a0STobias Hieta parser.error(message="missing CTU directory") 149d9cf8291SDaniel Hwang # Check CTU capability via checking clang-extdef-mapping 150d9cf8291SDaniel Hwang if not is_ctu_capable(args.extdef_map_cmd): 151*dd3c26a0STobias Hieta parser.error( 152*dd3c26a0STobias Hieta message="""This version of clang does not support CTU 153*dd3c26a0STobias Hieta functionality or clang-extdef-mapping command not found.""" 154*dd3c26a0STobias Hieta ) 155d9cf8291SDaniel Hwang 156d9cf8291SDaniel Hwang 157d9cf8291SDaniel Hwangdef create_intercept_parser(): 158d9cf8291SDaniel Hwang """Creates a parser for command-line arguments to 'intercept'.""" 159d9cf8291SDaniel Hwang 160d9cf8291SDaniel Hwang parser = create_default_parser() 161d9cf8291SDaniel Hwang parser_add_cdb(parser) 162d9cf8291SDaniel Hwang 163d9cf8291SDaniel Hwang parser_add_prefer_wrapper(parser) 164d9cf8291SDaniel Hwang parser_add_compilers(parser) 165d9cf8291SDaniel Hwang 166*dd3c26a0STobias Hieta advanced = parser.add_argument_group("advanced options") 167d9cf8291SDaniel Hwang group = advanced.add_mutually_exclusive_group() 168d9cf8291SDaniel Hwang group.add_argument( 169*dd3c26a0STobias Hieta "--append", 170*dd3c26a0STobias Hieta action="store_true", 171d9cf8291SDaniel Hwang help="""Extend existing compilation database with new entries. 172d9cf8291SDaniel Hwang Duplicate entries are detected and not present in the final output. 173d9cf8291SDaniel Hwang The output is not continuously updated, it's done when the build 174*dd3c26a0STobias Hieta command finished. """, 175*dd3c26a0STobias Hieta ) 176d9cf8291SDaniel Hwang 177d9cf8291SDaniel Hwang parser.add_argument( 178*dd3c26a0STobias Hieta dest="build", nargs=argparse.REMAINDER, help="""Command to run.""" 179*dd3c26a0STobias Hieta ) 180d9cf8291SDaniel Hwang return parser 181d9cf8291SDaniel Hwang 182d9cf8291SDaniel Hwang 183d9cf8291SDaniel Hwangdef create_analyze_parser(from_build_command): 184d9cf8291SDaniel Hwang """Creates a parser for command-line arguments to 'analyze'.""" 185d9cf8291SDaniel Hwang 186d9cf8291SDaniel Hwang parser = create_default_parser() 187d9cf8291SDaniel Hwang 188d9cf8291SDaniel Hwang if from_build_command: 189d9cf8291SDaniel Hwang parser_add_prefer_wrapper(parser) 190d9cf8291SDaniel Hwang parser_add_compilers(parser) 191d9cf8291SDaniel Hwang 192d9cf8291SDaniel Hwang parser.add_argument( 193*dd3c26a0STobias Hieta "--intercept-first", 194*dd3c26a0STobias Hieta action="store_true", 195d9cf8291SDaniel Hwang help="""Run the build commands first, intercept compiler 196d9cf8291SDaniel Hwang calls and then run the static analyzer afterwards. 197d9cf8291SDaniel Hwang Generally speaking it has better coverage on build commands. 198d9cf8291SDaniel Hwang With '--override-compiler' it use compiler wrapper, but does 199*dd3c26a0STobias Hieta not run the analyzer till the build is finished.""", 200*dd3c26a0STobias Hieta ) 201d9cf8291SDaniel Hwang else: 202d9cf8291SDaniel Hwang parser_add_cdb(parser) 203d9cf8291SDaniel Hwang 204d9cf8291SDaniel Hwang parser.add_argument( 205*dd3c26a0STobias Hieta "--status-bugs", 206*dd3c26a0STobias Hieta action="store_true", 207d9cf8291SDaniel Hwang help="""The exit status of '%(prog)s' is the same as the executed 208d9cf8291SDaniel Hwang build command. This option ignores the build exit status and sets to 209*dd3c26a0STobias Hieta be non zero if it found potential bugs or zero otherwise.""", 210*dd3c26a0STobias Hieta ) 211d9cf8291SDaniel Hwang parser.add_argument( 212*dd3c26a0STobias Hieta "--exclude", 213*dd3c26a0STobias Hieta metavar="<directory>", 214*dd3c26a0STobias Hieta dest="excludes", 215*dd3c26a0STobias Hieta action="append", 216d9cf8291SDaniel Hwang default=[], 217d9cf8291SDaniel Hwang help="""Do not run static analyzer against files found in this 218d9cf8291SDaniel Hwang directory. (You can specify this option multiple times.) 219*dd3c26a0STobias Hieta Could be useful when project contains 3rd party libraries.""", 220*dd3c26a0STobias Hieta ) 221d9cf8291SDaniel Hwang 222*dd3c26a0STobias Hieta output = parser.add_argument_group("output control options") 223d9cf8291SDaniel Hwang output.add_argument( 224*dd3c26a0STobias Hieta "--output", 225*dd3c26a0STobias Hieta "-o", 226*dd3c26a0STobias Hieta metavar="<path>", 227d9cf8291SDaniel Hwang default=tempfile.gettempdir(), 228d9cf8291SDaniel Hwang help="""Specifies the output directory for analyzer reports. 229*dd3c26a0STobias Hieta Subdirectory will be created if default directory is targeted.""", 230*dd3c26a0STobias Hieta ) 231d9cf8291SDaniel Hwang output.add_argument( 232*dd3c26a0STobias Hieta "--keep-empty", 233*dd3c26a0STobias Hieta action="store_true", 234d9cf8291SDaniel Hwang help="""Don't remove the build results directory even if no issues 235*dd3c26a0STobias Hieta were reported.""", 236*dd3c26a0STobias Hieta ) 237d9cf8291SDaniel Hwang output.add_argument( 238*dd3c26a0STobias Hieta "--html-title", 239*dd3c26a0STobias Hieta metavar="<title>", 240d9cf8291SDaniel Hwang help="""Specify the title used on generated HTML pages. 241*dd3c26a0STobias Hieta If not specified, a default title will be used.""", 242*dd3c26a0STobias Hieta ) 243d9cf8291SDaniel Hwang format_group = output.add_mutually_exclusive_group() 244d9cf8291SDaniel Hwang format_group.add_argument( 245*dd3c26a0STobias Hieta "--plist", 246*dd3c26a0STobias Hieta "-plist", 247*dd3c26a0STobias Hieta dest="output_format", 248*dd3c26a0STobias Hieta const="plist", 249*dd3c26a0STobias Hieta default="html", 250*dd3c26a0STobias Hieta action="store_const", 251*dd3c26a0STobias Hieta help="""Cause the results as a set of .plist files.""", 252*dd3c26a0STobias Hieta ) 253d9cf8291SDaniel Hwang format_group.add_argument( 254*dd3c26a0STobias Hieta "--plist-html", 255*dd3c26a0STobias Hieta "-plist-html", 256*dd3c26a0STobias Hieta dest="output_format", 257*dd3c26a0STobias Hieta const="plist-html", 258*dd3c26a0STobias Hieta default="html", 259*dd3c26a0STobias Hieta action="store_const", 260*dd3c26a0STobias Hieta help="""Cause the results as a set of .html and .plist files.""", 261*dd3c26a0STobias Hieta ) 262d9cf8291SDaniel Hwang format_group.add_argument( 263*dd3c26a0STobias Hieta "--plist-multi-file", 264*dd3c26a0STobias Hieta "-plist-multi-file", 265*dd3c26a0STobias Hieta dest="output_format", 266*dd3c26a0STobias Hieta const="plist-multi-file", 267*dd3c26a0STobias Hieta default="html", 268*dd3c26a0STobias Hieta action="store_const", 269d9cf8291SDaniel Hwang help="""Cause the results as a set of .plist files with extra 270*dd3c26a0STobias Hieta information on related files.""", 271*dd3c26a0STobias Hieta ) 272d9cf8291SDaniel Hwang format_group.add_argument( 273*dd3c26a0STobias Hieta "--sarif", 274*dd3c26a0STobias Hieta "-sarif", 275*dd3c26a0STobias Hieta dest="output_format", 276*dd3c26a0STobias Hieta const="sarif", 277*dd3c26a0STobias Hieta default="html", 278*dd3c26a0STobias Hieta action="store_const", 279*dd3c26a0STobias Hieta help="""Cause the results as a result.sarif file.""", 280*dd3c26a0STobias Hieta ) 281d9cf8291SDaniel Hwang format_group.add_argument( 282*dd3c26a0STobias Hieta "--sarif-html", 283*dd3c26a0STobias Hieta "-sarif-html", 284*dd3c26a0STobias Hieta dest="output_format", 285*dd3c26a0STobias Hieta const="sarif-html", 286*dd3c26a0STobias Hieta default="html", 287*dd3c26a0STobias Hieta action="store_const", 288*dd3c26a0STobias Hieta help="""Cause the results as a result.sarif file and .html files.""", 289*dd3c26a0STobias Hieta ) 290d9cf8291SDaniel Hwang 291*dd3c26a0STobias Hieta advanced = parser.add_argument_group("advanced options") 292d9cf8291SDaniel Hwang advanced.add_argument( 293*dd3c26a0STobias Hieta "--use-analyzer", 294*dd3c26a0STobias Hieta metavar="<path>", 295*dd3c26a0STobias Hieta dest="clang", 296*dd3c26a0STobias Hieta default="clang", 297d9cf8291SDaniel Hwang help="""'%(prog)s' uses the 'clang' executable relative to itself for 298d9cf8291SDaniel Hwang static analysis. One can override this behavior with this option by 299*dd3c26a0STobias Hieta using the 'clang' packaged with Xcode (on OS X) or from the PATH.""", 300*dd3c26a0STobias Hieta ) 301d9cf8291SDaniel Hwang advanced.add_argument( 302*dd3c26a0STobias Hieta "--no-failure-reports", 303*dd3c26a0STobias Hieta "-no-failure-reports", 304*dd3c26a0STobias Hieta dest="output_failures", 305*dd3c26a0STobias Hieta action="store_false", 306d9cf8291SDaniel Hwang help="""Do not create a 'failures' subdirectory that includes analyzer 307*dd3c26a0STobias Hieta crash reports and preprocessed source files.""", 308*dd3c26a0STobias Hieta ) 309d9cf8291SDaniel Hwang parser.add_argument( 310*dd3c26a0STobias Hieta "--analyze-headers", 311*dd3c26a0STobias Hieta action="store_true", 312d9cf8291SDaniel Hwang help="""Also analyze functions in #included files. By default, such 313d9cf8291SDaniel Hwang functions are skipped unless they are called by functions within the 314*dd3c26a0STobias Hieta main source file.""", 315*dd3c26a0STobias Hieta ) 316d9cf8291SDaniel Hwang advanced.add_argument( 317*dd3c26a0STobias Hieta "--stats", 318*dd3c26a0STobias Hieta "-stats", 319*dd3c26a0STobias Hieta action="store_true", 320*dd3c26a0STobias Hieta help="""Generates visitation statistics for the project.""", 321*dd3c26a0STobias Hieta ) 322d9cf8291SDaniel Hwang advanced.add_argument( 323*dd3c26a0STobias Hieta "--internal-stats", 324*dd3c26a0STobias Hieta action="store_true", 325*dd3c26a0STobias Hieta help="""Generate internal analyzer statistics.""", 326*dd3c26a0STobias Hieta ) 327d9cf8291SDaniel Hwang advanced.add_argument( 328*dd3c26a0STobias Hieta "--maxloop", 329*dd3c26a0STobias Hieta "-maxloop", 330*dd3c26a0STobias Hieta metavar="<loop count>", 331d9cf8291SDaniel Hwang type=int, 332d9cf8291SDaniel Hwang help="""Specify the number of times a block can be visited before 333d9cf8291SDaniel Hwang giving up. Increase for more comprehensive coverage at a cost of 334*dd3c26a0STobias Hieta speed.""", 335*dd3c26a0STobias Hieta ) 336d9cf8291SDaniel Hwang advanced.add_argument( 337*dd3c26a0STobias Hieta "--store", 338*dd3c26a0STobias Hieta "-store", 339*dd3c26a0STobias Hieta metavar="<model>", 340*dd3c26a0STobias Hieta dest="store_model", 341*dd3c26a0STobias Hieta choices=["region", "basic"], 342d9cf8291SDaniel Hwang help="""Specify the store model used by the analyzer. 'region' 343d9cf8291SDaniel Hwang specifies a field- sensitive store model. 'basic' which is far less 344d9cf8291SDaniel Hwang precise but can more quickly analyze code. 'basic' was the default 345*dd3c26a0STobias Hieta store model for checker-0.221 and earlier.""", 346*dd3c26a0STobias Hieta ) 347d9cf8291SDaniel Hwang advanced.add_argument( 348*dd3c26a0STobias Hieta "--constraints", 349*dd3c26a0STobias Hieta "-constraints", 350*dd3c26a0STobias Hieta metavar="<model>", 351*dd3c26a0STobias Hieta dest="constraints_model", 352*dd3c26a0STobias Hieta choices=["range", "basic"], 353d9cf8291SDaniel Hwang help="""Specify the constraint engine used by the analyzer. Specifying 354d9cf8291SDaniel Hwang 'basic' uses a simpler, less powerful constraint model used by 355*dd3c26a0STobias Hieta checker-0.160 and earlier.""", 356*dd3c26a0STobias Hieta ) 357d9cf8291SDaniel Hwang advanced.add_argument( 358*dd3c26a0STobias Hieta "--analyzer-config", 359*dd3c26a0STobias Hieta "-analyzer-config", 360*dd3c26a0STobias Hieta metavar="<options>", 361d9cf8291SDaniel Hwang help="""Provide options to pass through to the analyzer's 362d9cf8291SDaniel Hwang -analyzer-config flag. Several options are separated with comma: 363d9cf8291SDaniel Hwang 'key1=val1,key2=val2' 364d9cf8291SDaniel Hwang 365d9cf8291SDaniel Hwang Available options: 366d9cf8291SDaniel Hwang stable-report-filename=true or false (default) 367d9cf8291SDaniel Hwang 368d9cf8291SDaniel Hwang Switch the page naming to: 369d9cf8291SDaniel Hwang report-<filename>-<function/method name>-<id>.html 370*dd3c26a0STobias Hieta instead of report-XXXXXX.html""", 371*dd3c26a0STobias Hieta ) 372d9cf8291SDaniel Hwang advanced.add_argument( 373*dd3c26a0STobias Hieta "--force-analyze-debug-code", 374*dd3c26a0STobias Hieta dest="force_debug", 375*dd3c26a0STobias Hieta action="store_true", 376d9cf8291SDaniel Hwang help="""Tells analyzer to enable assertions in code even if they were 377*dd3c26a0STobias Hieta disabled during compilation, enabling more precise results.""", 378*dd3c26a0STobias Hieta ) 379d9cf8291SDaniel Hwang 380*dd3c26a0STobias Hieta plugins = parser.add_argument_group("checker options") 381d9cf8291SDaniel Hwang plugins.add_argument( 382*dd3c26a0STobias Hieta "--load-plugin", 383*dd3c26a0STobias Hieta "-load-plugin", 384*dd3c26a0STobias Hieta metavar="<plugin library>", 385*dd3c26a0STobias Hieta dest="plugins", 386*dd3c26a0STobias Hieta action="append", 387*dd3c26a0STobias Hieta help="""Loading external checkers using the clang plugin interface.""", 388*dd3c26a0STobias Hieta ) 389d9cf8291SDaniel Hwang plugins.add_argument( 390*dd3c26a0STobias Hieta "--enable-checker", 391*dd3c26a0STobias Hieta "-enable-checker", 392*dd3c26a0STobias Hieta metavar="<checker name>", 393d9cf8291SDaniel Hwang action=AppendCommaSeparated, 394*dd3c26a0STobias Hieta help="""Enable specific checker.""", 395*dd3c26a0STobias Hieta ) 396d9cf8291SDaniel Hwang plugins.add_argument( 397*dd3c26a0STobias Hieta "--disable-checker", 398*dd3c26a0STobias Hieta "-disable-checker", 399*dd3c26a0STobias Hieta metavar="<checker name>", 400d9cf8291SDaniel Hwang action=AppendCommaSeparated, 401*dd3c26a0STobias Hieta help="""Disable specific checker.""", 402*dd3c26a0STobias Hieta ) 403d9cf8291SDaniel Hwang plugins.add_argument( 404*dd3c26a0STobias Hieta "--help-checkers", 405*dd3c26a0STobias Hieta action="store_true", 406d9cf8291SDaniel Hwang help="""A default group of checkers is run unless explicitly disabled. 407d9cf8291SDaniel Hwang Exactly which checkers constitute the default group is a function of 408*dd3c26a0STobias Hieta the operating system in use. These can be printed with this flag.""", 409*dd3c26a0STobias Hieta ) 410d9cf8291SDaniel Hwang plugins.add_argument( 411*dd3c26a0STobias Hieta "--help-checkers-verbose", 412*dd3c26a0STobias Hieta action="store_true", 413*dd3c26a0STobias Hieta help="""Print all available checkers and mark the enabled ones.""", 414*dd3c26a0STobias Hieta ) 415d9cf8291SDaniel Hwang 416d9cf8291SDaniel Hwang if from_build_command: 417d9cf8291SDaniel Hwang parser.add_argument( 418*dd3c26a0STobias Hieta dest="build", nargs=argparse.REMAINDER, help="""Command to run.""" 419*dd3c26a0STobias Hieta ) 420d9cf8291SDaniel Hwang else: 421*dd3c26a0STobias Hieta ctu = parser.add_argument_group("cross translation unit analysis") 422d9cf8291SDaniel Hwang ctu_mutex_group = ctu.add_mutually_exclusive_group() 423d9cf8291SDaniel Hwang ctu_mutex_group.add_argument( 424*dd3c26a0STobias Hieta "--ctu", 425*dd3c26a0STobias Hieta action="store_const", 426*dd3c26a0STobias Hieta const=CtuConfig(collect=True, analyze=True, dir="", extdef_map_cmd=""), 427*dd3c26a0STobias Hieta dest="ctu_phases", 428d9cf8291SDaniel Hwang help="""Perform cross translation unit (ctu) analysis (both collect 429d9cf8291SDaniel Hwang and analyze phases) using default <ctu-dir> for temporary output. 430*dd3c26a0STobias Hieta At the end of the analysis, the temporary directory is removed.""", 431*dd3c26a0STobias Hieta ) 432d9cf8291SDaniel Hwang ctu.add_argument( 433*dd3c26a0STobias Hieta "--ctu-dir", 434*dd3c26a0STobias Hieta metavar="<ctu-dir>", 435*dd3c26a0STobias Hieta dest="ctu_dir", 436*dd3c26a0STobias Hieta default="ctu-dir", 437d9cf8291SDaniel Hwang help="""Defines the temporary directory used between ctu 438*dd3c26a0STobias Hieta phases.""", 439*dd3c26a0STobias Hieta ) 440d9cf8291SDaniel Hwang ctu_mutex_group.add_argument( 441*dd3c26a0STobias Hieta "--ctu-collect-only", 442*dd3c26a0STobias Hieta action="store_const", 443*dd3c26a0STobias Hieta const=CtuConfig(collect=True, analyze=False, dir="", extdef_map_cmd=""), 444*dd3c26a0STobias Hieta dest="ctu_phases", 445d9cf8291SDaniel Hwang help="""Perform only the collect phase of ctu. 446*dd3c26a0STobias Hieta Keep <ctu-dir> for further use.""", 447*dd3c26a0STobias Hieta ) 448d9cf8291SDaniel Hwang ctu_mutex_group.add_argument( 449*dd3c26a0STobias Hieta "--ctu-analyze-only", 450*dd3c26a0STobias Hieta action="store_const", 451*dd3c26a0STobias Hieta const=CtuConfig(collect=False, analyze=True, dir="", extdef_map_cmd=""), 452*dd3c26a0STobias Hieta dest="ctu_phases", 453d9cf8291SDaniel Hwang help="""Perform only the analyze phase of ctu. <ctu-dir> should be 454*dd3c26a0STobias Hieta present and will not be removed after analysis.""", 455*dd3c26a0STobias Hieta ) 456d9cf8291SDaniel Hwang ctu.add_argument( 457*dd3c26a0STobias Hieta "--use-extdef-map-cmd", 458*dd3c26a0STobias Hieta metavar="<path>", 459*dd3c26a0STobias Hieta dest="extdef_map_cmd", 460*dd3c26a0STobias Hieta default="clang-extdef-mapping", 461d9cf8291SDaniel Hwang help="""'%(prog)s' uses the 'clang-extdef-mapping' executable 462d9cf8291SDaniel Hwang relative to itself for generating external definition maps for 463d9cf8291SDaniel Hwang static analysis. One can override this behavior with this option 464d9cf8291SDaniel Hwang by using the 'clang-extdef-mapping' packaged with Xcode (on OS X) 465*dd3c26a0STobias Hieta or from the PATH.""", 466*dd3c26a0STobias Hieta ) 467d9cf8291SDaniel Hwang return parser 468d9cf8291SDaniel Hwang 469d9cf8291SDaniel Hwang 470d9cf8291SDaniel Hwangdef create_default_parser(): 471d9cf8291SDaniel Hwang """Creates command line parser for all build wrapper commands.""" 472d9cf8291SDaniel Hwang 473d9cf8291SDaniel Hwang parser = argparse.ArgumentParser( 474*dd3c26a0STobias Hieta formatter_class=argparse.ArgumentDefaultsHelpFormatter 475*dd3c26a0STobias Hieta ) 476d9cf8291SDaniel Hwang 477d9cf8291SDaniel Hwang parser.add_argument( 478*dd3c26a0STobias Hieta "--verbose", 479*dd3c26a0STobias Hieta "-v", 480*dd3c26a0STobias Hieta action="count", 481d9cf8291SDaniel Hwang default=0, 482d9cf8291SDaniel Hwang help="""Enable verbose output from '%(prog)s'. A second, third and 483*dd3c26a0STobias Hieta fourth flags increases verbosity.""", 484*dd3c26a0STobias Hieta ) 485d9cf8291SDaniel Hwang return parser 486d9cf8291SDaniel Hwang 487d9cf8291SDaniel Hwang 488d9cf8291SDaniel Hwangdef parser_add_cdb(parser): 489d9cf8291SDaniel Hwang parser.add_argument( 490*dd3c26a0STobias Hieta "--cdb", 491*dd3c26a0STobias Hieta metavar="<file>", 492d9cf8291SDaniel Hwang default="compile_commands.json", 493*dd3c26a0STobias Hieta help="""The JSON compilation database.""", 494*dd3c26a0STobias Hieta ) 495d9cf8291SDaniel Hwang 496d9cf8291SDaniel Hwang 497d9cf8291SDaniel Hwangdef parser_add_prefer_wrapper(parser): 498d9cf8291SDaniel Hwang parser.add_argument( 499*dd3c26a0STobias Hieta "--override-compiler", 500*dd3c26a0STobias Hieta action="store_true", 501d9cf8291SDaniel Hwang help="""Always resort to the compiler wrapper even when better 502*dd3c26a0STobias Hieta intercept methods are available.""", 503*dd3c26a0STobias Hieta ) 504d9cf8291SDaniel Hwang 505d9cf8291SDaniel Hwang 506d9cf8291SDaniel Hwangdef parser_add_compilers(parser): 507d9cf8291SDaniel Hwang parser.add_argument( 508*dd3c26a0STobias Hieta "--use-cc", 509*dd3c26a0STobias Hieta metavar="<path>", 510*dd3c26a0STobias Hieta dest="cc", 511*dd3c26a0STobias Hieta default=os.getenv("CC", "cc"), 512d9cf8291SDaniel Hwang help="""When '%(prog)s' analyzes a project by interposing a compiler 513d9cf8291SDaniel Hwang wrapper, which executes a real compiler for compilation and do other 514d9cf8291SDaniel Hwang tasks (record the compiler invocation). Because of this interposing, 515d9cf8291SDaniel Hwang '%(prog)s' does not know what compiler your project normally uses. 516d9cf8291SDaniel Hwang Instead, it simply overrides the CC environment variable, and guesses 517d9cf8291SDaniel Hwang your default compiler. 518d9cf8291SDaniel Hwang 519d9cf8291SDaniel Hwang If you need '%(prog)s' to use a specific compiler for *compilation* 520*dd3c26a0STobias Hieta then you can use this option to specify a path to that compiler.""", 521*dd3c26a0STobias Hieta ) 522d9cf8291SDaniel Hwang parser.add_argument( 523*dd3c26a0STobias Hieta "--use-c++", 524*dd3c26a0STobias Hieta metavar="<path>", 525*dd3c26a0STobias Hieta dest="cxx", 526*dd3c26a0STobias Hieta default=os.getenv("CXX", "c++"), 527*dd3c26a0STobias Hieta help="""This is the same as "--use-cc" but for C++ code.""", 528*dd3c26a0STobias Hieta ) 529d9cf8291SDaniel Hwang 530d9cf8291SDaniel Hwang 531d9cf8291SDaniel Hwangclass AppendCommaSeparated(argparse.Action): 532d9cf8291SDaniel Hwang """argparse Action class to support multiple comma separated lists.""" 533d9cf8291SDaniel Hwang 534d9cf8291SDaniel Hwang def __call__(self, __parser, namespace, values, __option_string): 535d9cf8291SDaniel Hwang # getattr(obj, attr, default) does not really returns default but none 536d9cf8291SDaniel Hwang if getattr(namespace, self.dest, None) is None: 537d9cf8291SDaniel Hwang setattr(namespace, self.dest, []) 538d9cf8291SDaniel Hwang # once it's fixed we can use as expected 539d9cf8291SDaniel Hwang actual = getattr(namespace, self.dest) 540*dd3c26a0STobias Hieta actual.extend(values.split(",")) 541d9cf8291SDaniel Hwang setattr(namespace, self.dest, actual) 542d9cf8291SDaniel Hwang 543d9cf8291SDaniel Hwang 544d9cf8291SDaniel Hwangdef print_active_checkers(checkers): 545d9cf8291SDaniel Hwang """Print active checkers to stdout.""" 546d9cf8291SDaniel Hwang 547*dd3c26a0STobias Hieta for name in sorted(name for name, (_, active) in checkers.items() if active): 548d9cf8291SDaniel Hwang print(name) 549d9cf8291SDaniel Hwang 550d9cf8291SDaniel Hwang 551d9cf8291SDaniel Hwangdef print_checkers(checkers): 552d9cf8291SDaniel Hwang """Print verbose checker help to stdout.""" 553d9cf8291SDaniel Hwang 554*dd3c26a0STobias Hieta print("") 555*dd3c26a0STobias Hieta print("available checkers:") 556*dd3c26a0STobias Hieta print("") 557d9cf8291SDaniel Hwang for name in sorted(checkers.keys()): 558d9cf8291SDaniel Hwang description, active = checkers[name] 559*dd3c26a0STobias Hieta prefix = "+" if active else " " 560d9cf8291SDaniel Hwang if len(name) > 30: 561*dd3c26a0STobias Hieta print(" {0} {1}".format(prefix, name)) 562*dd3c26a0STobias Hieta print(" " * 35 + description) 563d9cf8291SDaniel Hwang else: 564*dd3c26a0STobias Hieta print(" {0} {1: <30} {2}".format(prefix, name, description)) 565*dd3c26a0STobias Hieta print("") 566d9cf8291SDaniel Hwang print('NOTE: "+" indicates that an analysis is enabled by default.') 567*dd3c26a0STobias Hieta print("") 568