xref: /llvm-project/clang/tools/scan-build-py/lib/libscanbuild/arguments.py (revision dd3c26a045c081620375a878159f536758baba6e)
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